-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsync.go
138 lines (118 loc) · 2.99 KB
/
sync.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package sets
import (
"encoding/json"
"fmt"
"iter"
"slices"
"sync"
)
// SyncMap is a concurrency safe set type that uses a sync.Map.
type SyncMap[M comparable] struct {
m sync.Map
}
var _ Set[int] = new(SyncMap[int])
// NewSyncMap returns an empty Set[M] that is backed by a sync.Map, making it safe for concurrent use.
// Please read the documentation for [sync.Map] to understand the behavior of modifying the map.
func NewSyncMap[M comparable]() *SyncMap[M] {
return &SyncMap[M]{
m: sync.Map{},
}
}
// NewSyncMapFrom returns a new Set[M] filled with the values from the sequence and is backed by a sync.Map, making it safe
// for concurrent use. Please read the documentation for [sync.Map] to understand the behavior of modifying the map.
func NewSyncMapFrom[M comparable](seq iter.Seq[M]) *SyncMap[M] {
s := NewSyncMap[M]()
for x := range seq {
s.Add(x)
}
return s
}
// NewSyncMapWith returns a new Set[M] filled with the values provided and is backed by a sync.Map, making it safe
// for concurrent use. Please read the documentation for [sync.Map] to understand the behavior of modifying the map.
func NewSyncMapWith[M comparable](m ...M) *SyncMap[M] {
return NewSyncMapFrom(slices.Values(m))
}
func (s *SyncMap[M]) Contains(m M) bool {
_, ok := s.m.Load(m)
return ok
}
func (s *SyncMap[M]) Clear() int {
var n int
s.m.Range(func(_, _ interface{}) bool {
n++
return true
})
s.m.Clear()
return n
}
func (s *SyncMap[M]) Add(m M) bool {
_, loaded := s.m.LoadOrStore(m, struct{}{})
return !loaded
}
func (s *SyncMap[M]) Pop() (M, bool) {
var m M
var ok bool
s.m.Range(func(key, _ interface{}) bool {
if _, ok = s.m.LoadAndDelete(key); ok {
m = key.(M)
ok = true
return false
}
return true
})
return m, ok
}
func (s *SyncMap[M]) Remove(m M) bool {
_, ok := s.m.LoadAndDelete(m)
return ok
}
func (s *SyncMap[M]) Cardinality() int {
if s == nil {
return 0
}
var n int
s.m.Range(func(_, _ interface{}) bool {
n++
return true
})
return n
}
// Iterator yields all elements in the set. It is safe to call concurrently with other methods, but the order and
// behavior is undefined, as per [sync.Map]'s `Range`.
func (s *SyncMap[M]) Iterator(yield func(M) bool) {
s.m.Range(func(key, _ interface{}) bool {
return yield(key.(M))
})
}
func (s *SyncMap[M]) Clone() Set[M] {
return NewSyncMapFrom(s.Iterator)
}
func (s *SyncMap[M]) NewEmpty() Set[M] {
return NewSyncMap[M]()
}
func (s *SyncMap[M]) String() string {
var m M
return fmt.Sprintf("SyncSet[%T](%v)", m, slices.Collect(s.Iterator))
}
func (s *SyncMap[M]) MarshalJSON() ([]byte, error) {
v := slices.Collect(s.Iterator)
if len(v) == 0 {
return []byte("[]"), nil
}
d, err := json.Marshal(v)
if err != nil {
return d, fmt.Errorf("marshaling sync set: %w", err)
}
return d, nil
}
func (s *SyncMap[M]) UnmarshalJSON(d []byte) error {
var x []M
if err := json.Unmarshal(d, &x); err != nil {
return fmt.Errorf("unmarshaling sync set: %w", err)
}
s.m.Clear()
for _, m := range x {
s.Add(m)
}
return nil
}