mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-11-06 18:27:20 -05:00
98 lines
1.5 KiB
Go
98 lines
1.5 KiB
Go
|
package d2core
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
type cacheNode struct {
|
||
|
next *cacheNode
|
||
|
prev *cacheNode
|
||
|
key string
|
||
|
value interface{}
|
||
|
weight int
|
||
|
}
|
||
|
|
||
|
type cache struct {
|
||
|
head *cacheNode
|
||
|
tail *cacheNode
|
||
|
lookup map[string]*cacheNode
|
||
|
weight int
|
||
|
budget int
|
||
|
mutex sync.Mutex
|
||
|
}
|
||
|
|
||
|
func createCache(budget int) *cache {
|
||
|
return &cache{lookup: make(map[string]*cacheNode), budget: budget}
|
||
|
}
|
||
|
|
||
|
func (c *cache) insert(key string, value interface{}, weight int) error {
|
||
|
c.mutex.Lock()
|
||
|
defer c.mutex.Unlock()
|
||
|
|
||
|
if _, found := c.lookup[key]; found {
|
||
|
return errors.New("key already exists in cache")
|
||
|
}
|
||
|
|
||
|
node := &cacheNode{
|
||
|
key: key,
|
||
|
value: value,
|
||
|
weight: weight,
|
||
|
next: c.head,
|
||
|
}
|
||
|
|
||
|
if c.head != nil {
|
||
|
c.head.prev = node
|
||
|
}
|
||
|
|
||
|
c.head = node
|
||
|
if c.tail == nil {
|
||
|
c.tail = node
|
||
|
}
|
||
|
|
||
|
c.lookup[key] = node
|
||
|
c.weight += node.weight
|
||
|
|
||
|
for ; c.tail != nil && c.tail != c.head && c.weight > c.budget; c.tail = c.tail.prev {
|
||
|
c.weight -= c.tail.weight
|
||
|
c.tail.prev.next = nil
|
||
|
delete(c.lookup, c.tail.key)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *cache) retrieve(key string) (interface{}, bool) {
|
||
|
c.mutex.Lock()
|
||
|
defer c.mutex.Unlock()
|
||
|
|
||
|
node, found := c.lookup[key]
|
||
|
if !found {
|
||
|
return nil, false
|
||
|
}
|
||
|
|
||
|
if node != c.head {
|
||
|
if node.next != nil {
|
||
|
node.next.prev = node.prev
|
||
|
}
|
||
|
if node.prev != nil {
|
||
|
node.prev.next = node.next
|
||
|
}
|
||
|
|
||
|
if node == c.tail {
|
||
|
c.tail = c.tail.prev
|
||
|
}
|
||
|
|
||
|
node.next = c.head
|
||
|
node.prev = nil
|
||
|
|
||
|
if c.head != nil {
|
||
|
c.head.prev = node
|
||
|
}
|
||
|
|
||
|
c.head = node
|
||
|
}
|
||
|
|
||
|
return node.value, true
|
||
|
}
|