Skip to content

Commit 486e6d1

Browse files
committed
update the readme and regen the files, also add a uint64 cmap by default.
1 parent dbeddf4 commit 486e6d1

File tree

4 files changed

+454
-29
lines changed

4 files changed

+454
-29
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ CMap (concurrent-map) is a sharded map implementation to support fast concurrent
1515
* `stringcmap.CMap` gives a specialized version to support map[string]interface{}.
1616
* `stringcmap.MapWithJSON` implements json.Unmarshaler with a custom value unmarshaler.
1717

18+
## Typed CMap (using [genx](https://github.com/OneOfOne/genx))
19+
20+
* CMap fully supports generating typed versions, for example [`stringcmap`](https://github.com/OneOfOne/cmap/tree/master/stringcmap)
21+
is generated by running `go:generate genx -pkg github.com/OneOfOne/cmap -v -n stringcmap -t KT=string,VT=interface{} -fld HashFn -fn DefaultKeyHasher -s "cm.HashFn=hashers.Fnv32" -m -o ./stringcmap/cmap_string_iface.go`
22+
### How to generate your own?
23+
```
24+
➤ go get -u github.com/OneOfOne/genx/cmd/genx # get or update genx
25+
➤ genx -pkg github.com/OneOfOne/cmap -v -m -t KT=pkg.SomeType,VT=interface{} -name newPackageName -o ./cmap_something.go
26+
# example:
27+
➤ genx -pkg github.com/OneOfOne/cmap -v -m -t KT=uint64,VT=func() -name cbmap -o ./cmap_cbmap.go
28+
```
1829
## FAQ
1930

2031
### Why?

cmap_iface_iface.go

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// This file was automatically generated by genx.
22
// Any changes will be lost if this file is regenerated.
33
// see https://github.com/OneOfOne/genx
4-
// cmd: genx -pkg github.com/OneOfOne/cmap -v -t KT=interface{},VT=interface{} -m -o ./cmap_iface_iface.go
4+
// cmd: genx -pkg github.com/OneOfOne/cmap -v -m -t KT=interface{},VT=interface{} -o ./cmap_iface_iface.go
55
// +build !genx
66

77
package cmap
@@ -20,8 +20,6 @@ const DefaultShardCount = 1 << 8
2020
type CMap struct {
2121
shards []*LMap
2222
keysPool sync.Pool
23-
// HashFn allows using a custom hash function that's used to determain the key's shard. Defaults to DefaultKeyHasher.
24-
HashFn func(interface{}) uint32
2523
}
2624

2725
// New is an alias for NewSize(DefaultShardCount)
@@ -40,7 +38,6 @@ func NewSize(shardCount int) *CMap {
4038

4139
cm := &CMap{
4240
shards: make([]*LMap, shardCount),
43-
HashFn: DefaultKeyHasher,
4441
}
4542

4643
cm.keysPool.New = func() interface{} {
@@ -58,63 +55,63 @@ func NewSize(shardCount int) *CMap {
5855

5956
// ShardForKey returns the LMap that may hold the specific key.
6057
func (cm *CMap) ShardForKey(key interface{}) *LMap {
61-
h := cm.HashFn(key)
58+
h := hasher(key)
6259
return cm.shards[h&uint32(len(cm.shards)-1)]
6360
}
6461

6562
// Set is the equivalent of `map[key] = val`.
6663
func (cm *CMap) Set(key interface{}, val interface{}) {
67-
h := cm.HashFn(key)
64+
h := hasher(key)
6865
cm.shards[h&uint32(len(cm.shards)-1)].Set(key, val)
6966
}
7067

7168
// SetIfNotExists will only assign val to key if it wasn't already set.
7269
// Use `Update` if you need more logic.
7370
func (cm *CMap) SetIfNotExists(key interface{}, val interface{}) (set bool) {
74-
h := cm.HashFn(key)
71+
h := hasher(key)
7572
return cm.shards[h&uint32(len(cm.shards)-1)].SetIfNotExists(key, val)
7673
}
7774

7875
// Get is the equivalent of `val := map[key]`.
7976
func (cm *CMap) Get(key interface{}) (val interface{}) {
80-
h := cm.HashFn(key)
77+
h := hasher(key)
8178
return cm.shards[h&uint32(len(cm.shards)-1)].Get(key)
8279
}
8380

8481
// GetOK is the equivalent of `val, ok := map[key]`.
8582
func (cm *CMap) GetOK(key interface{}) (val interface{}, ok bool) {
86-
h := cm.HashFn(key)
83+
h := hasher(key)
8784
return cm.shards[h&uint32(len(cm.shards)-1)].GetOK(key)
8885
}
8986

9087
// Has is the equivalent of `_, ok := map[key]`.
9188
func (cm *CMap) Has(key interface{}) bool {
92-
h := cm.HashFn(key)
89+
h := hasher(key)
9390
return cm.shards[h&uint32(len(cm.shards)-1)].Has(key)
9491
}
9592

9693
// Delete is the equivalent of `delete(map, key)`.
9794
func (cm *CMap) Delete(key interface{}) {
98-
h := cm.HashFn(key)
95+
h := hasher(key)
9996
cm.shards[h&uint32(len(cm.shards)-1)].Delete(key)
10097
}
10198

10299
// DeleteAndGet is the equivalent of `oldVal := map[key]; delete(map, key)`.
103100
func (cm *CMap) DeleteAndGet(key interface{}) interface{} {
104-
h := cm.HashFn(key)
101+
h := hasher(key)
105102
return cm.shards[h&uint32(len(cm.shards)-1)].DeleteAndGet(key)
106103
}
107104

108105
// Update calls `fn` with the key's old value (or nil) and assign the returned value to the key.
109106
// The shard containing the key will be locked, it is NOT safe to call other cmap funcs inside `fn`.
110107
func (cm *CMap) Update(key interface{}, fn func(oldval interface{}) (newval interface{})) {
111-
h := cm.HashFn(key)
108+
h := hasher(key)
112109
cm.shards[h&uint32(len(cm.shards)-1)].Update(key, fn)
113110
}
114111

115112
// Swap is the equivalent of `oldVal, map[key] = map[key], newVal`.
116113
func (cm *CMap) Swap(key interface{}, val interface{}) interface{} {
117-
h := cm.HashFn(key)
114+
h := hasher(key)
118115
return cm.shards[h&uint32(len(cm.shards)-1)].Swap(key, val)
119116
}
120117

@@ -166,6 +163,19 @@ func (cm *CMap) Len() int {
166163
return ln
167164
}
168165

166+
// ShardDistribution returns the distribution of data amoung all shards.
167+
// Useful for debugging the efficiency of a hash.
168+
func (cm *CMap) ShardDistribution() []float64 {
169+
var (
170+
out = make([]float64, len(cm.shards))
171+
ln = float64(cm.Len())
172+
)
173+
for i := range out {
174+
out[i] = float64(cm.shards[i].Len()) / ln
175+
}
176+
return out
177+
}
178+
169179
// KV holds the key/value returned when Iter is called.
170180
type KV struct {
171181
Key interface{}
@@ -217,8 +227,7 @@ func (cm *CMap) iterContext(ctx context.Context, ch chan<- *KV, locked bool) {
217227
// NumShards returns the number of shards in the map.
218228
func (cm *CMap) NumShards() int { return len(cm.shards) }
219229

220-
// DefaultKeyHasher is an alias for hashers.TypeHasher32(key).
221-
func DefaultKeyHasher(key interface{}) uint32 { return hashers.TypeHasher32(key) }
230+
func hasher(key interface{}) uint32 { return hashers.TypeHasher32(key) }
222231

223232
// LMap is a simple sync.RWMutex locked map.
224233
// Used by CMap internally for sharding.
@@ -232,7 +241,7 @@ func NewLMap() *LMap {
232241
return NewLMapSize(0)
233242
}
234243

235-
// NewLMapSize is the equivalent of `m := make(map[KT]VT, cap)`
244+
// NewLMapSize is the equivalent of `m := make(map[interface{}]interface{}, cap)`
236245
func NewLMapSize(cap int) *LMap {
237246
return &LMap{
238247
m: make(map[interface{}]interface{}, cap),

stringcmap/cmap_string_iface.go

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// This file was automatically generated by genx.
22
// Any changes will be lost if this file is regenerated.
33
// see https://github.com/OneOfOne/genx
4-
// cmd: genx -pkg github.com/OneOfOne/cmap -v -n stringcmap -t KT=string,VT=interface{} -fld HashFn -fn DefaultKeyHasher -s cm.HashFn=hashers.Fnv32 -m -o ./stringcmap/cmap_string_iface.go
4+
// cmd: genx -pkg github.com/OneOfOne/cmap -v -m -n stringcmap -t KT=string,VT=interface{} -o ./stringcmap/cmap_string_iface.go
55
// +build !genx
66

77
package stringcmap
@@ -55,63 +55,63 @@ func NewSize(shardCount int) *CMap {
5555

5656
// ShardForKey returns the LMap that may hold the specific key.
5757
func (cm *CMap) ShardForKey(key string) *LMap {
58-
h := hashers.Fnv32(key)
58+
h := hasher(key)
5959
return cm.shards[h&uint32(len(cm.shards)-1)]
6060
}
6161

6262
// Set is the equivalent of `map[key] = val`.
6363
func (cm *CMap) Set(key string, val interface{}) {
64-
h := hashers.Fnv32(key)
64+
h := hasher(key)
6565
cm.shards[h&uint32(len(cm.shards)-1)].Set(key, val)
6666
}
6767

6868
// SetIfNotExists will only assign val to key if it wasn't already set.
6969
// Use `Update` if you need more logic.
7070
func (cm *CMap) SetIfNotExists(key string, val interface{}) (set bool) {
71-
h := hashers.Fnv32(key)
71+
h := hasher(key)
7272
return cm.shards[h&uint32(len(cm.shards)-1)].SetIfNotExists(key, val)
7373
}
7474

7575
// Get is the equivalent of `val := map[key]`.
7676
func (cm *CMap) Get(key string) (val interface{}) {
77-
h := hashers.Fnv32(key)
77+
h := hasher(key)
7878
return cm.shards[h&uint32(len(cm.shards)-1)].Get(key)
7979
}
8080

8181
// GetOK is the equivalent of `val, ok := map[key]`.
8282
func (cm *CMap) GetOK(key string) (val interface{}, ok bool) {
83-
h := hashers.Fnv32(key)
83+
h := hasher(key)
8484
return cm.shards[h&uint32(len(cm.shards)-1)].GetOK(key)
8585
}
8686

8787
// Has is the equivalent of `_, ok := map[key]`.
8888
func (cm *CMap) Has(key string) bool {
89-
h := hashers.Fnv32(key)
89+
h := hasher(key)
9090
return cm.shards[h&uint32(len(cm.shards)-1)].Has(key)
9191
}
9292

9393
// Delete is the equivalent of `delete(map, key)`.
9494
func (cm *CMap) Delete(key string) {
95-
h := hashers.Fnv32(key)
95+
h := hasher(key)
9696
cm.shards[h&uint32(len(cm.shards)-1)].Delete(key)
9797
}
9898

9999
// DeleteAndGet is the equivalent of `oldVal := map[key]; delete(map, key)`.
100100
func (cm *CMap) DeleteAndGet(key string) interface{} {
101-
h := hashers.Fnv32(key)
101+
h := hasher(key)
102102
return cm.shards[h&uint32(len(cm.shards)-1)].DeleteAndGet(key)
103103
}
104104

105105
// Update calls `fn` with the key's old value (or nil) and assign the returned value to the key.
106106
// The shard containing the key will be locked, it is NOT safe to call other cmap funcs inside `fn`.
107107
func (cm *CMap) Update(key string, fn func(oldval interface{}) (newval interface{})) {
108-
h := hashers.Fnv32(key)
108+
h := hasher(key)
109109
cm.shards[h&uint32(len(cm.shards)-1)].Update(key, fn)
110110
}
111111

112112
// Swap is the equivalent of `oldVal, map[key] = map[key], newVal`.
113113
func (cm *CMap) Swap(key string, val interface{}) interface{} {
114-
h := hashers.Fnv32(key)
114+
h := hasher(key)
115115
return cm.shards[h&uint32(len(cm.shards)-1)].Swap(key, val)
116116
}
117117

@@ -163,6 +163,19 @@ func (cm *CMap) Len() int {
163163
return ln
164164
}
165165

166+
// ShardDistribution returns the distribution of data amoung all shards.
167+
// Useful for debugging the efficiency of a hash.
168+
func (cm *CMap) ShardDistribution() []float64 {
169+
var (
170+
out = make([]float64, len(cm.shards))
171+
ln = float64(cm.Len())
172+
)
173+
for i := range out {
174+
out[i] = float64(cm.shards[i].Len()) / ln
175+
}
176+
return out
177+
}
178+
166179
// KV holds the key/value returned when Iter is called.
167180
type KV struct {
168181
Key string
@@ -213,6 +226,7 @@ func (cm *CMap) iterContext(ctx context.Context, ch chan<- *KV, locked bool) {
213226

214227
// NumShards returns the number of shards in the map.
215228
func (cm *CMap) NumShards() int { return len(cm.shards) }
229+
func hasher(key string) uint32 { return hashers.Fnv32(key) }
216230

217231
// LMap is a simple sync.RWMutex locked map.
218232
// Used by CMap internally for sharding.
@@ -226,7 +240,7 @@ func NewLMap() *LMap {
226240
return NewLMapSize(0)
227241
}
228242

229-
// NewLMapSize is the equivalent of `m := make(map[KT]VT, cap)`
243+
// NewLMapSize is the equivalent of `m := make(map[string]interface{}, cap)`
230244
func NewLMapSize(cap int) *LMap {
231245
return &LMap{
232246
m: make(map[string]interface{}, cap),

0 commit comments

Comments
 (0)