-
Notifications
You must be signed in to change notification settings - Fork 6
/
lrucache.lua
139 lines (115 loc) · 3.28 KB
/
lrucache.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
--[=[
Size-limited LRU cache in Lua.
Written by Cosmin Apreutesei. Public Domain.
Values can have different sizes. When a new value is put in the cache and
the cache is full, just enough old values are removed to make room for the
new value and not exceed the cache max size.
lrucache([options]) -> cache create a new cache
cache.max_size <- size set the cache size limit
cache:clear() clear the cache
cache:free() destroy the cache
cache:free_value(val) value destructor (to be overriden)
cache:value_size(val) -> size get value size (to be overriden; returns 1)
cache:free_size() -> size size left until `max_size`
cache:get(key) -> val get a value from the cache by key
cache:remove(key) -> val remove a value from the cache by key
cache:remove_val(val) -> key remove a value from the cache
cache:remove_last() -> val remove the last value from the cache
cache:put(key, val) put a value in the cache, making room as needed
]=]
require'linkedlist'
local lrucache = {}
lrucache.__index = lrucache
lrucache.max_size = 1
function lrucache:clear()
if self.keys then
for val in pairs(self.keys) do
self:free_value(val)
end
end
self.lru = linkedlist()
self.values = {} --{key -> val}
self.keys = {} --{val -> key}
self.total_size = 0
return self
end
function _G.lrucache(t)
local self = setmetatable(t or {}, lrucache)
return self:clear()
end
setmetatable(lrucache, {__call = lrucache.new})
function lrucache:free()
if self.keys then
for val in pairs(self.keys) do
self:free_value(val)
end
self.lru = false
self.values = false
self.keys = false
self.total_size = 0
end
end
function lrucache:free_size()
return self.max_size - self.total_size
end
function lrucache:value_size(val) return 1 end --stub, size must be >= 0 always
function lrucache:free_value(val) end --stub
function lrucache:get(key)
local val = self.values[key]
if not val then return nil end
self.lru:remove(val)
self.lru:insert_first(val)
return val
end
function lrucache:_remove(key, val)
local val_size = self:value_size(val)
self.lru:remove(val)
self:free_value(val)
self.values[key] = nil
self.keys[val] = nil
self.total_size = self.total_size - val_size
end
function lrucache:remove(key)
local val = self.values[key]
if not val then return nil end
self:_remove(key, val)
return val
end
function lrucache:remove_val(val)
local key = self.keys[val]
if not key then return nil end
self:_remove(key, val)
return key
end
function lrucache:remove_last()
local val = self.lru.last
if not val then return nil end
self:_remove(self.keys[val], val)
return val
end
function lrucache:put(key, val)
local val_size = self:value_size(val)
local old_val = self.values[key]
if old_val then
self.lru:remove(old_val)
self.keys[old_val] = nil
self.total_size = self.total_size - val_size
end
while self.lru.last and self.total_size + val_size > self.max_size do
self:remove_last()
end
self.values[key] = val
self.keys[val] = key
self.lru:insert_first(val)
self.total_size = self.total_size + val_size
end
if not ... then
local cache = _G.lrucache()
local k1 = {}
local v1 = {}
local v2 = {}
local v3 = {}
cache:put(k1, v1)
cache:put(k1, v2)
cache:put(k1, v3)
end