1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 22:30:04 +08:00
SpaceVim/bundle/cmp-dictionary/lua/cmp_dictionary/lfu.lua
2023-06-11 21:41:39 +08:00

133 lines
3.0 KiB
Lua

---@class CacheNode
---@field key integer
---@field value integer
---@field freq integer
---@field prev CacheNode
---@field next CacheNode
local CacheNode = {}
---Initialize the cache node
---@param key any
---@param value any
---@return CacheNode
function CacheNode.init(key, value)
return {
key = key,
value = value,
freq = 1,
prev = nil,
next = nil,
}
end
---@class LinkedList
---@field head CacheNode
---@field tail CacheNode
---@field length integer
local LinkedList = {}
---Initialize the linked list
---@return LinkedList
function LinkedList.init()
local self = {}
self.head = CacheNode.init(0, 0) -- dummy
self.tail = CacheNode.init(0, 0) -- dummy
self.head.next = self.tail
self.tail.prev = self.head
self.length = 0
return setmetatable(self, { __index = LinkedList })
end
---Add node
---@param node CacheNode
function LinkedList:add(node)
node.prev = self.head
node.next = self.head.next
self.head.next = node
node.next.prev = node
self.length = self.length + 1
end
---Remove node
---@param node CacheNode
function LinkedList:remove(node)
node.prev.next = node.next
node.next.prev = node.prev
self.length = self.length - 1
end
---@class LfuCache
---@field capacity integer
---@field key2node table<any, CacheNode>
---@field list_map table<integer, LinkedList>
---@field total_size integer
---@field min_freq integer
local LfuCache = {}
---Initialize the cache
---@param capacity integer
---@return LfuCache
function LfuCache.init(capacity)
local self = {}
self.capacity = capacity
self.key2node = {}
self.list_map = { LinkedList.init() }
self.total_size = 0
self.min_freq = 0
return setmetatable(self, { __index = LfuCache })
end
---Add a data to the cache
---@param key any
---@param value any
function LfuCache:set(key, value)
if self.key2node[key] then
local node = self.key2node[key]
node.value = value
self:_update(node)
else
if self.total_size == self.capacity then
local last_node = self.list_map[self.min_freq].tail.prev
self.key2node[last_node.key] = nil
self.list_map[self.min_freq]:remove(last_node)
self.total_size = self.total_size - 1
end
local new_node = CacheNode.init(key, value)
self.key2node[key] = new_node
self.list_map[1]:add(new_node)
self.min_freq = 1
self.total_size = self.total_size + 1
end
end
---Fetching a data from the cache
---@param key any
---@return any
function LfuCache:get(key)
if self.key2node[key] then
local node = self.key2node[key]
self:_update(node)
return node.value
end
end
---Update the number of accesses to a node
---@param node CacheNode
function LfuCache:_update(node)
local cur_freq = node.freq
self.list_map[cur_freq]:remove(node)
node.freq = cur_freq + 1
if not self.list_map[node.freq] then
self.list_map[node.freq] = LinkedList.init()
end
self.list_map[node.freq]:add(node)
if self.list_map[self.min_freq].length == 0 then
self.min_freq = cur_freq + 1
end
end
return LfuCache