Files
go-cuckoo/bucket.go
M.V. Hutz 56b1982f8a
All checks were successful
CI / Makefile Lint (push) Successful in 16s
CI / Go Lint (push) Successful in 21s
CI / Unit Tests (push) Successful in 15s
CI / Fuzz Tests (push) Successful in 49s
CI / Mutation Tests (push) Successful in 55s
feat: add drop key functionality (#6)
Currently, the `Table.Drop()` function is deprecated because it is not implemented yet. Let's add that functionality.

- Adds true drop functionality to the table, through `Table.Drop()`.
- Adds tests for functionality.
- Rewrites fuzz test using `go_fuzz_utils`, to test arbitrary usage patterns.
- Rewrite `bucket` to allow a capacity of zero.
- Rename `Table.Capacity()` to `Table.TotalCapacity()`, to reflect to different between the capacity of the buckets vs. the whole table.
- Enforce 100% mutation test coverage.

Reviewed-on: #6
Co-authored-by: M.V. Hutz <git@maximhutz.me>
Co-committed-by: M.V. Hutz <git@maximhutz.me>
2026-03-20 01:59:54 +00:00

104 lines
1.9 KiB
Go

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