in shardedlru.go [60:114]
func NewShardedWithSize[K comparable, V any](shards, capacity, size uint32,
hash HashKeyCallback[K]) (
*ShardedLRU[K, V], error) {
if capacity == 0 {
return nil, errors.New("capacity must be positive")
}
if size < capacity {
return nil, fmt.Errorf("size (%d) is smaller than capacity (%d)", size, capacity)
}
if size < 1<<31 {
size = nextPowerOfTwo(size) // next power of 2 so the LRUs can avoid costly divisions
} else {
size = 1 << 31 // the highest 2^N value that fits in a uint32
}
shards = nextPowerOfTwo(shards) // next power of 2 so we can avoid costly division for sharding
for shards > size/16 {
shards /= 16
}
if shards == 0 {
shards = 1
}
size /= shards // size per LRU
if size == 0 {
size = 1
}
capacity = (capacity + shards - 1) / shards // size per LRU
if capacity == 0 {
capacity = 1
}
lrus := make([]LRU[K, V], shards)
buckets := make([]uint32, size*shards)
elements := make([]element[K, V], size*shards)
from := 0
to := int(size)
for i := range lrus {
initLRU(&lrus[i], capacity, size, hash, buckets[from:to], elements[from:to])
from = to
to += int(size)
}
return &ShardedLRU[K, V]{
lrus: lrus,
mus: make([]sync.RWMutex, shards),
hash: hash,
shards: shards,
mask: shards - 1,
}, nil
}