Skip to content

Commit 0cc7eec

Browse files
committed
add Update func
1 parent 3b2a840 commit 0cc7eec

2 files changed

Lines changed: 121 additions & 96 deletions

File tree

cmap.go

Lines changed: 19 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ import (
1010
"sync/atomic"
1111
)
1212

13-
// IgnoreValue can be returned from the func called to NewFromJSON to ignore setting the value
14-
var IgnoreValue = &struct{ bool }{true}
13+
var (
14+
// IgnoreValue can be returned from the func called to NewFromJSON to ignore setting the value
15+
IgnoreValue = &struct{ bool }{true}
16+
// DeleteValue can be returns from Update to delete the value
17+
DeleteValue = &struct{ bool }{true}
18+
)
1519

1620
// DefaultShardCount is the default number of shards to use when New() or NewFromJSON() are called.
1721
const DefaultShardCount = 1 << 4 // 16
@@ -20,94 +24,7 @@ const DefaultShardCount = 1 << 4 // 16
2024
type ForEachFunc func(key string, val interface{}) (BreakEarly bool)
2125

2226
type CompareAndSwapFunc func(a, b interface{}) bool
23-
24-
type lockedMap struct {
25-
m map[string]interface{}
26-
l sync.RWMutex
27-
}
28-
29-
func (ms *lockedMap) Set(key string, v interface{}) {
30-
ms.l.Lock()
31-
ms.m[key] = v
32-
ms.l.Unlock()
33-
}
34-
35-
func (ms *lockedMap) Swap(key string, v interface{}) interface{} {
36-
ms.l.Lock()
37-
ov := ms.m[key]
38-
ms.m[key] = v
39-
ms.l.Unlock()
40-
return ov
41-
}
42-
43-
func (ms *lockedMap) CompareAndSwap(key string, v interface{}, casFn CompareAndSwapFunc) bool {
44-
ms.l.Lock()
45-
ov := ms.m[key]
46-
ok := casFn(v, ov)
47-
if ok {
48-
ms.m[key] = v
49-
}
50-
ms.l.Unlock()
51-
return ok
52-
}
53-
54-
func (ms *lockedMap) Get(key string) interface{} {
55-
ms.l.RLock()
56-
v := ms.m[key]
57-
ms.l.RUnlock()
58-
return v
59-
}
60-
61-
func (ms *lockedMap) Has(key string) bool {
62-
ms.l.RLock()
63-
_, ok := ms.m[key]
64-
ms.l.RUnlock()
65-
return ok
66-
}
67-
68-
func (ms *lockedMap) Delete(key string) {
69-
ms.l.Lock()
70-
delete(ms.m, key)
71-
ms.l.Unlock()
72-
}
73-
74-
func (ms *lockedMap) DeleteAndGet(key string) interface{} {
75-
ms.l.Lock()
76-
v := ms.m[key]
77-
delete(ms.m, key)
78-
ms.l.Unlock()
79-
return v
80-
}
81-
82-
func (ms *lockedMap) Len() int {
83-
ms.l.RLock()
84-
ln := len(ms.m)
85-
ms.l.RUnlock()
86-
return ln
87-
}
88-
89-
func (ms *lockedMap) ForEach(fn ForEachFunc) {
90-
ms.l.RLock()
91-
for k, v := range ms.m {
92-
if fn(k, v) {
93-
break
94-
}
95-
}
96-
ms.l.RUnlock()
97-
}
98-
99-
func (ms *lockedMap) iter(ch KeyValueChan, wg *sync.WaitGroup) {
100-
var kv KeyValue
101-
ms.l.RLock()
102-
for k, v := range ms.m {
103-
kv.Key, kv.Value = k, v
104-
if !ch.send(&kv) {
105-
break
106-
}
107-
}
108-
ms.l.RUnlock()
109-
wg.Done()
110-
}
27+
type UpdateFunc func(oldVal interface{}) (newVal interface{})
11128

11229
// CMap is a sharded thread-safe concurrent map.
11330
type CMap struct {
@@ -188,7 +105,13 @@ func (cm CMap) Has(key string) bool { return cm.shard(key).Has(k
188105
func (cm CMap) Delete(key string) { cm.shard(key).Delete(key) }
189106
func (cm CMap) DeleteAndGet(key string) interface{} { return cm.shard(key).DeleteAndGet(key) }
190107

191-
func (cm CMap) Swap(key string, val interface{}) interface{} { return cm.shard(key).Swap(key, val) }
108+
func (cm CMap) Update(key string, fn func(ov interface{}) interface{}) {
109+
cm.shard(key).Update(key, fn)
110+
}
111+
func (cm CMap) Swap(key string, val interface{}) interface{} {
112+
return cm.shard(key).Swap(key, val)
113+
}
114+
192115
func (cm CMap) CompareAndSwap(key string, val interface{}, eqFn CompareAndSwapFunc) bool {
193116
return cm.shard(key).CompareAndSwap(key, val, eqFn)
194117
}
@@ -228,12 +151,12 @@ type KeyValue struct {
228151
Value interface{}
229152
}
230153

231-
// Iter is an alias for IterBuffered(1)
232-
func (cm CMap) Iter() KeyValueChan { return cm.IterBuffered(1) }
154+
// Iter is an alias for IterBuffered(0)
155+
func (cm CMap) Iter() KeyValueChan { return cm.IterBuffered(0) }
233156

234-
// IterBuffered returns a buffered channel sz, to return an unbuffered channel you can pass 1
235-
// calling breakLoop will close the channel and consume any remaining values in it.
236-
// note that calling breakLoop() will show as a race on the race detector but it's more or less a "safe" race,
157+
// IterBuffered returns a buffered channel sz, to return an unbuffered channel you can pass 0
158+
// ch.Break() on the returned channel can allow breaking early.
159+
// note that calling ch.Break() will show as a race on the race detector but it's more or less a "safe" race,
237160
// and it is the only clean way to break out of a channel.
238161
func (cm CMap) IterBuffered(sz int) KeyValueChan {
239162
ch := make(KeyValueChan, sz)

lockedMap.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package cmap
2+
3+
import "sync"
4+
5+
type lockedMap struct {
6+
m map[string]interface{}
7+
l sync.RWMutex
8+
}
9+
10+
func (ms *lockedMap) Set(key string, v interface{}) {
11+
ms.l.Lock()
12+
ms.m[key] = v
13+
ms.l.Unlock()
14+
}
15+
16+
func (ms *lockedMap) Update(key string, fn UpdateFunc) {
17+
ms.l.Lock()
18+
19+
if v := fn(ms.m[key]); v != DeleteValue {
20+
ms.m[key] = v
21+
} else {
22+
delete(ms.m, key)
23+
}
24+
ms.l.Unlock()
25+
}
26+
27+
func (ms *lockedMap) Swap(key string, v interface{}) interface{} {
28+
ms.l.Lock()
29+
ov := ms.m[key]
30+
ms.m[key] = v
31+
ms.l.Unlock()
32+
return ov
33+
}
34+
35+
func (ms *lockedMap) CompareAndSwap(key string, v interface{}, casFn CompareAndSwapFunc) bool {
36+
ms.l.Lock()
37+
ov := ms.m[key]
38+
ok := casFn(v, ov)
39+
if ok {
40+
ms.m[key] = v
41+
}
42+
ms.l.Unlock()
43+
return ok
44+
}
45+
46+
func (ms *lockedMap) Get(key string) interface{} {
47+
ms.l.RLock()
48+
v := ms.m[key]
49+
ms.l.RUnlock()
50+
return v
51+
}
52+
53+
func (ms *lockedMap) Has(key string) bool {
54+
ms.l.RLock()
55+
_, ok := ms.m[key]
56+
ms.l.RUnlock()
57+
return ok
58+
}
59+
60+
func (ms *lockedMap) Delete(key string) {
61+
ms.l.Lock()
62+
delete(ms.m, key)
63+
ms.l.Unlock()
64+
}
65+
66+
func (ms *lockedMap) DeleteAndGet(key string) interface{} {
67+
ms.l.Lock()
68+
v := ms.m[key]
69+
delete(ms.m, key)
70+
ms.l.Unlock()
71+
return v
72+
}
73+
74+
func (ms *lockedMap) Len() int {
75+
ms.l.RLock()
76+
ln := len(ms.m)
77+
ms.l.RUnlock()
78+
return ln
79+
}
80+
81+
func (ms *lockedMap) ForEach(fn ForEachFunc) {
82+
ms.l.RLock()
83+
for k, v := range ms.m {
84+
if fn(k, v) {
85+
break
86+
}
87+
}
88+
ms.l.RUnlock()
89+
}
90+
91+
func (ms *lockedMap) iter(ch KeyValueChan, wg *sync.WaitGroup) {
92+
var kv KeyValue
93+
ms.l.RLock()
94+
for k, v := range ms.m {
95+
kv.Key, kv.Value = k, v
96+
if !ch.send(&kv) {
97+
break
98+
}
99+
}
100+
ms.l.RUnlock()
101+
wg.Done()
102+
}

0 commit comments

Comments
 (0)