github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/cache/half.go (about) 1 package cache 2 3 type Half struct { 4 items []Entry 5 lookup map[Hash]int 6 currentSize int 7 maxSize int 8 evicted EvictFunc 9 } 10 11 func NewHalf(maxSize int, evicted EvictFunc) *Half { 12 return &Half{ 13 items: []Entry{}, 14 lookup: map[Hash]int{}, 15 currentSize: 0, 16 maxSize: maxSize, 17 evicted: evicted, 18 } 19 } 20 21 func NewHalfPrealloc(entries, maxSize int, evicted EvictFunc) *Half { 22 return &Half{ 23 items: make([]Entry, 0, entries), 24 lookup: make(map[Hash]int, entries), 25 currentSize: 0, 26 maxSize: maxSize, 27 evicted: evicted, 28 } 29 } 30 31 func (cache *Half) Add(hash Hash, size int) (ok bool) { 32 if size > cache.maxSize { 33 return false 34 } 35 36 cache.currentSize += size 37 for cache.currentSize > cache.maxSize { 38 cache.evict(len(cache.items) - 1) 39 } 40 41 index := len(cache.items) 42 cache.lookup[hash] = index 43 cache.items = append(cache.items, Entry{hash, size}) 44 cache.bump(index) 45 46 return true 47 } 48 49 func (cache *Half) bump(index int) { 50 // this could be randomized or use a power of two choices 51 cache.swap(index, index/2) 52 } 53 54 func (cache *Half) swap(a, b int) { 55 if a == b { 56 return 57 } 58 59 cache.items[a], cache.items[b] = cache.items[b], cache.items[a] 60 cache.lookup[cache.items[a].Hash] = a 61 cache.lookup[cache.items[b].Hash] = b 62 } 63 64 func (cache *Half) evict(index int) { 65 last := len(cache.items) - 1 66 cache.swap(index, last) 67 68 item := cache.items[last] 69 cache.items = cache.items[:last] 70 cache.currentSize -= item.Size 71 delete(cache.lookup, item.Hash) 72 73 if cache.evicted != nil { 74 cache.evicted(item) 75 } 76 } 77 78 func (cache *Half) Get(hash Hash) (e Entry, ok bool) { 79 index, ok := cache.lookup[hash] 80 if !ok { 81 return Entry{}, false 82 } 83 84 entry := cache.items[index] 85 cache.bump(index) 86 return entry, true 87 } 88 89 func (cache *Half) Remove(hash Hash) { 90 index, ok := cache.lookup[hash] 91 if !ok { 92 return 93 } 94 cache.evict(index) 95 } 96 97 func (cache *Half) Len() int { return len(cache.items) } 98 func (cache *Half) CurrentSize() int { return cache.currentSize } 99 func (cache *Half) MaxSize() int { return cache.maxSize }