-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocked.go
164 lines (133 loc) · 4.24 KB
/
locked.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package sets
import (
"encoding/json"
"fmt"
"iter"
"slices"
"sync"
)
// Locked is a concurrency safe wrapper around a Set[M]. It uses a read-write lock to allow multiple readers to access
// the set concurrently, but only one writer at a time. The set is not ordered and does not guarantee the order of
// elements when iterating over them. It is safe for concurrent use.
type Locked[M comparable] struct {
set Set[M]
sync.RWMutex
}
var _ Set[int] = new(Locked[int])
// NewLocked returns an empty *Locked[M] that is safe for concurrent use.
func NewLocked[M comparable]() *Locked[M] {
return &Locked[M]{set: New[M]()}
}
// NewLockedFrom returns a new *Locked[M] filled with the values from the sequence.
func NewLockedFrom[M comparable](seq iter.Seq[M]) *Locked[M] {
s := NewLocked[M]()
for x := range seq {
s.Add(x)
}
return s
}
// NewLockedWith returns a *Locked[M] with the values provided.
func NewLockedWith[M comparable](m ...M) *Locked[M] {
return NewLockedFrom(slices.Values(m))
}
// NewLockedWrapping returns a Set[M]. If set is already a locked set, then it is just returned as is. If set isn't a locked set
// then the returned set is wrapped so that it is safe for concurrent use.
func NewLockedWrapping[M comparable](set Set[M]) Set[M] {
if _, ok := set.(Locker); ok {
return set
}
lset := NewLocked[M]()
lset.set = set
return lset
}
// Contains returns true if the set contains the element.
func (s *Locked[M]) Contains(m M) bool {
s.RLock()
defer s.RUnlock()
return s.set.Contains(m)
}
// Clear the set and returns the number of elements removed.
func (s *Locked[M]) Clear() int {
s.Lock()
defer s.Unlock()
return s.set.Clear()
}
// Add an element to the set. Returns true if the element was added, false if it was already present.
func (s *Locked[M]) Add(m M) bool {
s.Lock()
defer s.Unlock()
return s.set.Add(m)
}
// Remove an element from the set. Returns true if the element was removed, false if it was not present.
func (s *Locked[M]) Remove(m M) bool {
s.Lock()
defer s.Unlock()
return s.set.Remove(m)
}
// Cardinality returns the number of elements in the set.
func (s *Locked[M]) Cardinality() int {
s.RLock()
defer s.RUnlock()
return s.set.Cardinality()
}
// Iterator yields all elements in the set. It holds a read lock for the duration of iteration. Calling any method that
// modifies the set while iteration is happening will block until the iteration is complete.
func (s *Locked[M]) Iterator(yield func(M) bool) {
s.RLock()
defer s.RUnlock()
s.set.Iterator(yield)
}
// Clone returns a new set of the same underlying type.
func (s *Locked[M]) Clone() Set[M] {
s.RLock()
defer s.RUnlock()
return NewLockedFrom(s.Iterator)
}
// NewEmpty returns a new empty set of the same underlying type.
func (s *Locked[M]) NewEmpty() Set[M] {
return NewLocked[M]()
}
// Pop removes and returns an element from the set. If the set is empty, it returns the zero value of M and false.
func (s *Locked[M]) Pop() (M, bool) {
s.Lock()
defer s.Unlock()
return s.set.Pop()
}
// String returns a string representation of the set. It returns a string of the form LockedSet[T](<elements>).
func (s *Locked[M]) String() string {
s.RLock()
defer s.RUnlock()
return "Locked" + s.set.String()
}
// MarshalJSON implements json.Marshaler. It will marshal the set into a JSON array of the elements in the set. If the
// set is empty an empty JSON array is returned.
func (s *Locked[M]) MarshalJSON() ([]byte, error) {
s.RLock()
defer s.RUnlock()
jm, ok := s.set.(json.Marshaler)
if !ok {
return nil, fmt.Errorf("cannot marshal set of type %T - not json.Marshaler", s.set)
}
d, err := jm.MarshalJSON()
if err != nil {
return d, fmt.Errorf("marshaling locked set: %w", err)
}
return d, nil
}
// UnmarshalJSON implements json.Unmarshaler. It expects a JSON array of the elements in the set. If the set is empty,
// it returns an empty set. If the JSON is invalid, it returns an error.
func (s *Locked[M]) UnmarshalJSON(d []byte) error {
s.Lock()
defer s.Unlock()
if s.set == nil {
s.set = New[M]()
}
um, ok := s.set.(json.Unmarshaler)
if !ok {
return fmt.Errorf("cannot unmarshal set of type %T - not json.Unmarshaler", s.set)
}
if err := um.UnmarshalJSON(d); err != nil {
return fmt.Errorf("unmarshaling locked set: %w", err)
}
return nil
}