Skip to content

Commit 5dff70d

Browse files
committed
polished
1 parent 9c8bd71 commit 5dff70d

File tree

5 files changed

+143
-133
lines changed

5 files changed

+143
-133
lines changed

methodAdd.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package stringset
2+
3+
// Add adds a string to the set.
4+
// If string is already in the set, it has no effect.
5+
func (s *StringSet) Add(str string) {
6+
s.lock.Lock()
7+
s.m[str] = struct{}{}
8+
s.lock.Unlock()
9+
}
10+
11+
// AddSlice adds the elements of the slice to the set.
12+
func (s *StringSet) AddSlice(slice []string) *StringSet {
13+
s.lock.Lock()
14+
for _, str := range slice {
15+
s.m[str] = struct{}{}
16+
}
17+
s.lock.Unlock()
18+
19+
return s
20+
}

methodIntersect.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package stringset
2+
3+
import "sync"
4+
5+
// Intersect returns a new set which contains only the elemets shared
6+
// by both sets.
7+
func (s *StringSet) Intersect(other *StringSet) *StringSet {
8+
9+
var wg sync.WaitGroup
10+
11+
var slen, otherlen int
12+
13+
wg.Add(2)
14+
go func() {
15+
defer wg.Done()
16+
s.lock.Lock()
17+
slen = len(s.m)
18+
s.lock.Unlock()
19+
}()
20+
go func() {
21+
defer wg.Done()
22+
other.lock.Lock()
23+
otherlen = len(other.m)
24+
other.lock.Unlock()
25+
}()
26+
wg.Wait()
27+
28+
var intersection *StringSet
29+
switch {
30+
case slen >= otherlen:
31+
intersection = createIntersect(otherlen, other, s)
32+
33+
default:
34+
intersection = createIntersect(slen, s, other)
35+
}
36+
return intersection
37+
}
38+
39+
func createIntersect(smallerlen int, smaller, greater *StringSet) *StringSet {
40+
ret := &StringSet{
41+
m: make(map[string]struct{}, smallerlen),
42+
}
43+
// Copy smaller set in ret
44+
smaller.lock.Lock()
45+
for str := range smaller.m {
46+
ret.m[str] = struct{}{}
47+
}
48+
smaller.lock.Unlock()
49+
50+
greater.lock.Lock()
51+
defer greater.lock.Unlock()
52+
for element := range ret.m {
53+
// If element in smaller exists also in greater moves along
54+
if _, exists := greater.m[element]; exists {
55+
continue
56+
}
57+
// otherwise deletes it also from ret
58+
ret.lock.Lock()
59+
delete(ret.m, element)
60+
ret.lock.Unlock()
61+
}
62+
return ret
63+
}

stringset.go

Lines changed: 22 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ import (
66
"sync"
77
)
88

9-
// StringSet is a set of unique strings.
10-
// The lock sync.RWMutex allows to solve concurrency issues
11-
type StringSet struct {
12-
m map[string]struct{}
13-
lock sync.RWMutex
14-
}
15-
169
// New creates a new instance of type *Stringset
1710
func New() *StringSet {
1811
res := &StringSet{
@@ -22,36 +15,18 @@ func New() *StringSet {
2215
return res
2316
}
2417

25-
// AddSlice adds the elements of the slice to the set.
26-
func (s *StringSet) AddSlice(slice []string) *StringSet {
27-
28-
s.lock.Lock()
29-
defer s.lock.Unlock()
30-
31-
for _, str := range slice {
32-
s.m[str] = struct{}{}
33-
}
34-
35-
return s
36-
}
37-
3818
// NewStringSet creates a new set for strings.
3919
func NewStringSet(strings ...string) *StringSet {
4020
res := &StringSet{
4121
m: map[string]struct{}{},
4222
}
23+
res.lock.Lock()
4324
for _, s := range strings {
44-
res.Add(s)
25+
res.m[s] = struct{}{}
4526
}
46-
return res
47-
}
27+
res.lock.Unlock()
4828

49-
// Add adds a string to the set.
50-
// If string is already in the set, it has no effect.
51-
func (s *StringSet) Add(str string) {
52-
s.lock.Lock()
53-
s.m[str] = struct{}{}
54-
s.lock.Unlock()
29+
return res
5530
}
5631

5732
// Exists checks if string exists in the set.
@@ -102,25 +77,8 @@ func (s *StringSet) Contains(other *StringSet) bool {
10277
return true
10378
}
10479

105-
// Unify returns the first set which contains all elements of the two sets.
106-
func (s *StringSet) Unify(other *StringSet) {
107-
var wg sync.WaitGroup
108-
wg.Add(1)
109-
go func() {
110-
defer wg.Done()
111-
other.lock.Lock()
112-
for str := range other.m {
113-
s.lock.Lock()
114-
s.m[str] = struct{}{}
115-
s.lock.Unlock()
116-
}
117-
other.lock.Unlock()
118-
}()
119-
wg.Wait()
120-
}
121-
12280
// Union returns a new set which contains all elements of the previous ones.
123-
func (s *StringSet) Union(other *StringSet) (union *StringSet) {
81+
func (s *StringSet) Union(other *StringSet) *StringSet {
12482
var slen, otherlen int
12583
var wg sync.WaitGroup
12684
wg.Add(2)
@@ -178,92 +136,40 @@ func (s *StringSet) Len() int {
178136
return n
179137
}
180138

181-
// Pop removes and returns an arbitrary element from the set and removes it from the
182-
// set. If the set was empty, this returns ("", false).
183-
func (s *StringSet) Pop() (str string, ok bool) {
139+
// Pop returns and removes an arbitrary element from the set.
140+
// If the set is empty it returns "", false.
141+
func (s *StringSet) Pop() (string, bool) {
184142
s.lock.Lock()
185143
defer s.lock.Unlock()
186-
if len(s.m) != 0 {
144+
var str string
145+
switch len(s.m) {
146+
case 0:
147+
return "", false
148+
default:
187149
// deletes only one value from the set and than exits
188150
for str = range s.m {
189151
delete(s.m, str)
190-
return str, true
152+
break
191153
}
192154
}
193-
return "", false
155+
return str, true
194156
}
195157

196-
// Difference returns a new set with all elements from the first set and no elements from the latter.
197-
func (s *StringSet) Difference(other *StringSet) (diff *StringSet) {
198-
ret := &StringSet{
158+
// Difference returns a new set with all elements from the first set less
159+
// all elements from the second one.
160+
func (s *StringSet) Difference(other *StringSet) *StringSet {
161+
diff := &StringSet{
199162
m: map[string]struct{}{},
200163
}
201164
s.lock.Lock()
202165
for str := range s.m {
203-
ret.m[str] = struct{}{}
166+
diff.m[str] = struct{}{}
204167
}
205168
s.lock.Unlock()
206169
other.lock.Lock()
207170
for str := range other.m {
208-
delete(ret.m, str)
171+
delete(diff.m, str)
209172
}
210173
other.lock.Unlock()
211-
return ret
212-
}
213-
214-
// Intersect returns a new set which contains only the elemets shared by both input sets.
215-
func (s *StringSet) Intersect(other *StringSet) (intersection *StringSet) {
216-
var ret *StringSet
217-
var wg sync.WaitGroup
218-
219-
var slen, otherlen int
220-
221-
createIntersect := func(smallerlen int, smaller, greater *StringSet) (ret *StringSet) {
222-
ret = &StringSet{
223-
m: make(map[string]struct{}, smallerlen),
224-
}
225-
// Copy smaller set in ret
226-
smaller.lock.Lock()
227-
for str := range smaller.m {
228-
ret.m[str] = struct{}{}
229-
}
230-
smaller.lock.Unlock()
231-
232-
greater.lock.Lock()
233-
defer greater.lock.Unlock()
234-
for element := range ret.m {
235-
// If element in smaller exists also in greater moves along
236-
if _, exists := greater.m[element]; exists {
237-
continue
238-
}
239-
// otherwise deletes it also from ret
240-
ret.lock.Lock()
241-
delete(ret.m, element)
242-
ret.lock.Unlock()
243-
}
244-
return ret
245-
}
246-
247-
wg.Add(2)
248-
go func() {
249-
defer wg.Done()
250-
s.lock.Lock()
251-
slen = len(s.m)
252-
s.lock.Unlock()
253-
}()
254-
go func() {
255-
defer wg.Done()
256-
other.lock.Lock()
257-
otherlen = len(other.m)
258-
other.lock.Unlock()
259-
}()
260-
wg.Wait()
261-
switch {
262-
case slen >= otherlen:
263-
ret = createIntersect(otherlen, other, s)
264-
265-
case slen < otherlen:
266-
ret = createIntersect(slen, s, other)
267-
}
268-
return ret
174+
return diff
269175
}

stringset_test.go

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,45 @@ package stringset_test
22

33
import (
44
"fmt"
5-
"sort"
65
"reflect"
6+
"sort"
77
"testing"
88

99
"github.com/axamon/stringset"
1010
)
1111

1212
var tt = stringset.NewStringSet()
1313

14-
func ExampleStringSet_New() {
14+
func ExampleNew() {
1515

16-
s := stringset.New()
16+
s := stringset.New()
1717

1818
fmt.Println(reflect.TypeOf(s))
1919
// Output:
2020
// *stringset.StringSet
2121

2222
}
2323

24+
func ExampleNewStringSet() {
25+
s := stringset.NewStringSet("pippo", "pluto", "minnie")
26+
27+
slice := s.Strings()
28+
sort.Strings(slice)
29+
for _, element := range slice {
30+
fmt.Println(element)
31+
}
32+
// Output:
33+
// minnie
34+
// pippo
35+
// pluto
36+
}
2437

2538
func ExampleStringSet_AddSlice() {
2639
slice := []string{"pluto", "paperino", "pluto"}
2740

2841
s := stringset.New()
29-
30-
s.AddSlice(slice)
3142

32-
43+
s.AddSlice(slice)
3344

3445
fmt.Println(s.Len())
3546
// Output:
@@ -40,16 +51,16 @@ func BenchmarkT(b *testing.B) {
4051
var t = stringset.NewStringSet()
4152
var t1 = stringset.NewStringSet()
4253
for n := 0; n < b.N; n++ {
43-
go t.Add("pippo")
44-
go t1.Add("pluto")
45-
go t.Add("pluto")
46-
go t1.Add("paperino")
47-
go t.Len()
48-
go t.Union(t1)
49-
go t.Intersect(t1)
50-
go t.Exists("pippo")
51-
go t.Delete("pippo")
52-
go t.Pop()
54+
t.Add("pippo")
55+
t1.Add("pluto")
56+
t.Add("pluto")
57+
t1.Add("paperino")
58+
t.Len()
59+
t.Union(t1)
60+
t.Intersect(t1)
61+
t.Exists("pippo")
62+
t.Delete("pippo")
63+
t.Pop()
5364
}
5465
}
5566

@@ -71,7 +82,7 @@ func BenchmarkIntersect(b *testing.B) {
7182

7283
for n := 0; n < b.N; n++ {
7384

74-
go testSet.Intersect(testSet2)
85+
testSet.Intersect(testSet2)
7586

7687
}
7788
}

types.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package stringset
2+
3+
import "sync"
4+
5+
// StringSet is a set of unique strings.
6+
// The lock sync.RWMutex allows to solve concurrency issues.
7+
type StringSet struct {
8+
m map[string]struct{}
9+
lock sync.RWMutex
10+
}

0 commit comments

Comments
 (0)