mirror of
https://github.com/halfrost/LeetCode-Go.git
synced 2025-07-03 23:48:31 +08:00
177 lines
3.0 KiB
Go
177 lines
3.0 KiB
Go
package template
|
|
|
|
import (
|
|
"container/list"
|
|
"hash/fnv"
|
|
"sync"
|
|
)
|
|
|
|
type command int
|
|
|
|
const (
|
|
// MoveToFront define
|
|
MoveToFront command = iota
|
|
// PushFront define
|
|
PushFront
|
|
// Delete define
|
|
Delete
|
|
)
|
|
|
|
type clear struct {
|
|
done chan struct{}
|
|
}
|
|
|
|
// CLRUCache define: High Concurrency LRUCache
|
|
type CLRUCache struct {
|
|
sync.RWMutex
|
|
cap int
|
|
list *list.List
|
|
buckets []*bucket
|
|
bucketMask uint32
|
|
deletePairs chan *list.Element
|
|
movePairs chan *list.Element
|
|
control chan interface{}
|
|
}
|
|
|
|
// Pair define
|
|
type Pair struct {
|
|
key string
|
|
value interface{}
|
|
cmd command
|
|
}
|
|
|
|
// New define
|
|
func New(capacity int) *CLRUCache {
|
|
c := &CLRUCache{
|
|
cap: capacity,
|
|
list: list.New(),
|
|
bucketMask: uint32(1024) - 1,
|
|
buckets: make([]*bucket, 1024),
|
|
}
|
|
for i := 0; i < 1024; i++ {
|
|
c.buckets[i] = &bucket{
|
|
keys: make(map[string]*list.Element),
|
|
}
|
|
}
|
|
c.restart()
|
|
return c
|
|
}
|
|
|
|
// Get define
|
|
func (c *CLRUCache) Get(key string) interface{} {
|
|
el := c.bucket(key).get(key)
|
|
if el == nil {
|
|
return nil
|
|
}
|
|
c.move(el)
|
|
return el.Value.(Pair).value
|
|
}
|
|
|
|
// Put define
|
|
func (c *CLRUCache) Put(key string, value interface{}) {
|
|
el, exist := c.bucket(key).set(key, value)
|
|
if exist != nil {
|
|
c.deletePairs <- exist
|
|
}
|
|
c.move(el)
|
|
}
|
|
|
|
func (c *CLRUCache) move(el *list.Element) {
|
|
select {
|
|
case c.movePairs <- el:
|
|
default:
|
|
}
|
|
}
|
|
|
|
// Delete define
|
|
func (c *CLRUCache) Delete(key string) bool {
|
|
el := c.bucket(key).delete(key)
|
|
if el != nil {
|
|
c.deletePairs <- el
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Clear define
|
|
func (c *CLRUCache) Clear() {
|
|
done := make(chan struct{})
|
|
c.control <- clear{done: done}
|
|
<-done
|
|
}
|
|
|
|
// Count define
|
|
func (c *CLRUCache) Count() int {
|
|
count := 0
|
|
for _, b := range c.buckets {
|
|
count += b.pairCount()
|
|
}
|
|
return count
|
|
}
|
|
|
|
func (c *CLRUCache) bucket(key string) *bucket {
|
|
h := fnv.New32a()
|
|
h.Write([]byte(key))
|
|
return c.buckets[h.Sum32()&c.bucketMask]
|
|
}
|
|
|
|
func (c *CLRUCache) stop() {
|
|
close(c.movePairs)
|
|
<-c.control
|
|
}
|
|
|
|
func (c *CLRUCache) restart() {
|
|
c.deletePairs = make(chan *list.Element, 128)
|
|
c.movePairs = make(chan *list.Element, 128)
|
|
c.control = make(chan interface{})
|
|
go c.worker()
|
|
}
|
|
|
|
func (c *CLRUCache) worker() {
|
|
defer close(c.control)
|
|
for {
|
|
select {
|
|
case el, ok := <-c.movePairs:
|
|
if !ok {
|
|
goto clean
|
|
}
|
|
if c.doMove(el) && c.list.Len() > c.cap {
|
|
el := c.list.Back()
|
|
c.list.Remove(el)
|
|
c.bucket(el.Value.(Pair).key).delete(el.Value.(Pair).key)
|
|
}
|
|
case el := <-c.deletePairs:
|
|
c.list.Remove(el)
|
|
case control := <-c.control:
|
|
switch msg := control.(type) {
|
|
case clear:
|
|
for _, bucket := range c.buckets {
|
|
bucket.clear()
|
|
}
|
|
c.list = list.New()
|
|
msg.done <- struct{}{}
|
|
}
|
|
}
|
|
}
|
|
clean:
|
|
for {
|
|
select {
|
|
case el := <-c.deletePairs:
|
|
c.list.Remove(el)
|
|
default:
|
|
close(c.deletePairs)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *CLRUCache) doMove(el *list.Element) bool {
|
|
if el.Value.(Pair).cmd == MoveToFront {
|
|
c.list.MoveToFront(el)
|
|
return false
|
|
}
|
|
newel := c.list.PushFront(el.Value.(Pair))
|
|
c.bucket(el.Value.(Pair).key).update(el.Value.(Pair).key, newel)
|
|
return true
|
|
}
|