2021-12-04 16:42:11 +00:00

101 lines
1.7 KiB
Go

package concurrent
import (
"sync"
"sync/atomic"
"github.com/cespare/xxhash"
)
type bucket struct {
mux sync.RWMutex
values map[string]interface{}
}
func (b *bucket) Get(k string) (interface{}, bool) {
b.mux.RLock()
v, ok := b.values[k]
b.mux.RUnlock()
return v, ok
}
func (b *bucket) Set(k string, v interface{}) bool {
b.mux.Lock()
_, exsist := b.values[k]
b.values[k] = v
b.mux.Unlock()
return !exsist
}
func (b *bucket) Delete(k string) bool {
b.mux.Lock()
_, exsist := b.values[k]
delete(b.values, k)
b.mux.Unlock()
return exsist
}
func (b *bucket) forEach(f func(k string, v interface{}) bool) bool {
success := false
b.mux.RLock()
for k, v := range b.values {
success = f(k, v)
if !success {
break
}
}
b.mux.RUnlock()
return success
}
type Map struct {
size int64
buckets []*bucket
}
func (m *Map) Get(k string) (interface{}, bool) {
i := hash(k) % uint64(len(m.buckets))
return m.buckets[i].Get(k)
}
func (m *Map) Set(k string, v interface{}) {
i := hash(k) % uint64(len(m.buckets))
if m.buckets[i].Set(k, v) {
atomic.AddInt64(&m.size, 1)
}
}
func (m *Map) Delete(k string) {
i := hash(k) % uint64(len(m.buckets))
if m.buckets[i].Delete(k) {
atomic.AddInt64(&m.size, -1)
}
}
func (m *Map) Size() int64 {
return atomic.LoadInt64(&m.size)
}
func (m *Map) ForEach(f func(k string, v interface{}) bool) {
for _, b := range m.buckets {
if !b.forEach(f) {
return
}
}
}
func NewMap(bucketNum int) *Map {
if bucketNum <= 0 {
bucketNum = 64
}
m := &Map{buckets: make([]*bucket, bucketNum)}
for i := 0; i < bucketNum; i++ {
m.buckets[i] = &bucket{values: map[string]interface{}{}}
}
return m
}
func hash(k string) uint64 {
return xxhash.Sum64String(k)
}