v8.run/go/exp@v0.0.26-0.20230226010534-afcdbd3f782d/hashtable/table.go (about) 1 package hashtable 2 3 import ( 4 "math" 5 "sync" 6 "sync/atomic" 7 ) 8 9 type Table[K comparable, V any] struct { 10 hasher func(K) uint64 11 h atomic.Pointer[htab[K, V]] 12 version atomic.Uint64 13 14 mu sync.Mutex 15 } 16 17 func calcInitSize(a uint64) uint64 { 18 if int64(a) <= 256 { 19 a = 256 20 } 21 22 return 1 << uint64(math.Log2(float64(a))+2) 23 } 24 25 func New[K comparable, V any](size uint64, hasher func(K) uint64) *Table[K, V] { 26 ht := newHtab[K, V](calcInitSize(size)) 27 t := &Table[K, V]{ 28 hasher: hasher, 29 } 30 t.version.Store(1000) 31 ht.version = 1000 32 t.h.Store(ht) 33 34 return t 35 } 36 37 func (t *Table[K, V]) Delete(key K) { 38 hash := t.hasher(key) 39 40 for { 41 ht := t.h.Load() 42 if ht.count >= ht.size { 43 t.mu.Lock() 44 ht = t.h.Load() 45 if ht.count >= ht.size { 46 newh := newHtab[K, V](ht.size * 2) 47 newh.version = t.version.Add(1) 48 ht.copyto(newh) 49 t.h.Store(newh) 50 ht = newh 51 } 52 t.mu.Unlock() 53 } 54 55 ht.delete(hash, key) 56 57 if t.version.Load() == ht.version { 58 break 59 } 60 } 61 } 62 63 func (t *Table[K, V]) Lookup(key K) (value V, ok bool) { 64 ht := t.h.Load() 65 hash := t.hasher(key) 66 return ht.lookup(hash, key) 67 } 68 69 func (t *Table[K, V]) Insert(key K, value V) { 70 hash := t.hasher(key) 71 newkv := &kv[K, V]{ 72 Hash: hash, 73 Key: key, 74 Value: value, 75 } 76 77 for { 78 ht := t.h.Load() 79 if ht.count >= ht.size { 80 t.mu.Lock() 81 ht = t.h.Load() 82 if ht.count >= ht.size { 83 newh := newHtab[K, V](ht.size * 2) 84 newh.version = t.version.Add(1) 85 ht.copyto(newh) 86 t.h.Store(newh) 87 ht = newh 88 } 89 t.mu.Unlock() 90 } 91 92 ht.store(hash, newkv) 93 94 if t.version.Load() == ht.version { 95 break 96 } 97 } 98 }