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  }