package cuckoo // An Entry is a key-value pair. type Entry[K, V any] struct { Key K Value V } type slot[K, V any] struct { Entry[K, V] occupied bool } type subtable[K, V any] struct { hash Hash[K] slots []slot[K, V] capacity, size uint64 compare EqualFunc[K] } // location determines where in the subtable a certain key would be placed. If // the capacity is 0, this will panic. func (t *subtable[K, V]) location(key K) uint64 { return t.hash(key) % t.capacity } func (t *subtable[K, V]) get(key K) (value V, found bool) { if t.capacity == 0 { return } slot := t.slots[t.location(key)] return slot.Value, slot.occupied && t.compare(slot.Key, key) } func (t *subtable[K, V]) drop(key K) (occupied bool) { if t.capacity == 0 { return } slot := &t.slots[t.location(key)] if slot.occupied && t.compare(slot.Key, key) { slot.occupied = false t.size-- return true } return false } func (t *subtable[K, V]) resized(capacity uint64) *subtable[K, V] { return &subtable[K, V]{ slots: make([]slot[K, V], capacity), capacity: capacity, hash: t.hash, compare: t.compare, } } func (t *subtable[K, V]) update(key K, value V) (updated bool) { if t.capacity == 0 { return } slot := &t.slots[t.location(key)] if slot.occupied && t.compare(slot.Key, key) { slot.Value = value return true } return false } func (t *subtable[K, V]) insert(insertion Entry[K, V]) (evicted Entry[K, V], eviction bool) { if t.capacity == 0 { return insertion, true } slot := &t.slots[t.location(insertion.Key)] if !slot.occupied { slot.Entry = insertion slot.occupied = true t.size++ return } if t.compare(slot.Key, insertion.Key) { slot.Value = insertion.Value return } insertion, slot.Entry = slot.Entry, insertion return insertion, true } func newSubtable[K, V any](capacity uint64, hash Hash[K], compare EqualFunc[K]) *subtable[K, V] { return &subtable[K, V]{ hash: hash, capacity: capacity, compare: compare, size: 0, slots: make([]slot[K, V], capacity), } }