gotosocial/vendor/github.com/cornelk/hashmap/store.go
tobi bcb80d3ff4
[chore] bump gruf/go-store to v2 (#953)
* [chore] bump gruf/go-store to v2

* no more boobs
2022-11-05 11:10:19 +00:00

46 lines
1.7 KiB
Go

package hashmap
import (
"sync/atomic"
"unsafe"
)
type store[Key comparable, Value any] struct {
keyShifts uintptr // Pointer size - log2 of array size, to be used as index in the data array
count atomic.Uintptr // count of filled elements in the slice
array unsafe.Pointer // pointer to slice data array
index []*ListElement[Key, Value] // storage for the slice for the garbage collector to not clean it up
}
// item returns the item for the given hashed key.
func (s *store[Key, Value]) item(hashedKey uintptr) *ListElement[Key, Value] {
index := hashedKey >> s.keyShifts
ptr := (*unsafe.Pointer)(unsafe.Pointer(uintptr(s.array) + index*intSizeBytes))
item := (*ListElement[Key, Value])(atomic.LoadPointer(ptr))
return item
}
// adds an item to the index if needed and returns the new item counter if it changed, otherwise 0.
func (s *store[Key, Value]) addItem(item *ListElement[Key, Value]) uintptr {
index := item.keyHash >> s.keyShifts
ptr := (*unsafe.Pointer)(unsafe.Pointer(uintptr(s.array) + index*intSizeBytes))
for { // loop until the smallest key hash is in the index
element := (*ListElement[Key, Value])(atomic.LoadPointer(ptr)) // get the current item in the index
if element == nil { // no item yet at this index
if atomic.CompareAndSwapPointer(ptr, nil, unsafe.Pointer(item)) {
return s.count.Add(1)
}
continue // a new item was inserted concurrently, retry
}
if item.keyHash < element.keyHash {
// the new item is the smallest for this index?
if !atomic.CompareAndSwapPointer(ptr, unsafe.Pointer(element), unsafe.Pointer(item)) {
continue // a new item was inserted concurrently, retry
}
}
return 0
}
}