Comparison

util/cache.lua @ 6945:d779c55058c6

util.cache: Small update to prefix private fields with an underscore, add a :count() method (same as util.queue) and add an optional on_evict callback
author Matthew Wild <mwild1@gmail.com>
date Thu, 26 Nov 2015 00:07:48 +0000
parent 6943:0a31ec3193f0
child 7016:e0a0af42b09f
comparison
equal deleted inserted replaced
6944:62b6f6d230f1 6945:d779c55058c6
1 local cache_methods = {};
2 local cache_mt = { __index = cache_methods };
3
4 local function new(size)
5 size = assert(tonumber(size), "cache size must be a number");
6 size = math.floor(size);
7 assert(size > 0, "cache size must be greater than zero");
8 local data = {};
9 return setmetatable({ data = data, count = 0, size = size, head = nil, tail = nil }, cache_mt);
10 end
11 1
12 local function _remove(list, m) 2 local function _remove(list, m)
13 if m.prev then 3 if m.prev then
14 m.prev.next = m.next; 4 m.prev.next = m.next;
15 end 5 end
16 if m.next then 6 if m.next then
17 m.next.prev = m.prev; 7 m.next.prev = m.prev;
18 end 8 end
19 if list.tail == m then 9 if list._tail == m then
20 list.tail = m.prev; 10 list._tail = m.prev;
21 end 11 end
22 if list.head == m then 12 if list._head == m then
23 list.head = m.next; 13 list._head = m.next;
24 end 14 end
25 list.count = list.count - 1; 15 list._count = list._count - 1;
26 end 16 end
27 17
28 local function _insert(list, m) 18 local function _insert(list, m)
29 if list.head then 19 if list._head then
30 list.head.prev = m; 20 list._head.prev = m;
31 end 21 end
32 m.prev, m.next = nil, list.head; 22 m.prev, m.next = nil, list._head;
33 list.head = m; 23 list._head = m;
34 if not list.tail then 24 if not list._tail then
35 list.tail = m; 25 list._tail = m;
36 end 26 end
37 list.count = list.count + 1; 27 list._count = list._count + 1;
38 end 28 end
39 29
30 local cache_methods = {};
31 local cache_mt = { __index = cache_methods };
32
40 function cache_methods:set(k, v) 33 function cache_methods:set(k, v)
41 local m = self.data[k]; 34 local m = self._data[k];
42 if m then 35 if m then
43 -- Key already exists 36 -- Key already exists
44 if v ~= nil then 37 if v ~= nil then
45 -- Bump to head of list 38 -- Bump to head of list
46 _remove(self, m); 39 _remove(self, m);
47 _insert(self, m); 40 _insert(self, m);
48 m.value = v; 41 m.value = v;
49 else 42 else
50 -- Remove from list 43 -- Remove from list
51 _remove(self, m); 44 _remove(self, m);
52 self.data[k] = nil; 45 self._data[k] = nil;
53 end 46 end
54 return; 47 return true;
55 end 48 end
56 -- New key 49 -- New key
57 if v == nil then 50 if v == nil then
58 return; 51 return true;
59 end 52 end
60 -- Check whether we need to remove oldest k/v 53 -- Check whether we need to remove oldest k/v
61 if self.count == self.size then 54 if self._count == self.size then
62 self.data[self.tail.key] = nil; 55 local tail = self._tail;
63 _remove(self, self.tail); 56 local on_evict = self._on_evict;
57 if on_evict then
58 on_evict(tail.key, tail.value);
59 end
60 _remove(self, tail);
61 self._data[tail.key] = nil;
64 end 62 end
65 63
66 m = { key = k, value = v, prev = nil, next = nil }; 64 m = { key = k, value = v, prev = nil, next = nil };
67 self.data[k] = m; 65 self._data[k] = m;
68 _insert(self, m); 66 _insert(self, m);
67 return true;
69 end 68 end
70 69
71 function cache_methods:get(k) 70 function cache_methods:get(k)
72 local m = self.data[k]; 71 local m = self._data[k];
73 if m then 72 if m then
74 return m.value; 73 return m.value;
75 end 74 end
76 return nil; 75 return nil;
77 end 76 end
78 77
79 function cache_methods:items() 78 function cache_methods:items()
80 local m = self.head; 79 local m = self._head;
81 return function () 80 return function ()
82 if not m then 81 if not m then
83 return; 82 return;
84 end 83 end
85 local k, v = m.key, m.value; 84 local k, v = m.key, m.value;
86 m = m.next; 85 m = m.next;
87 return k, v; 86 return k, v;
88 end 87 end
89 end 88 end
90 89
90 function cache_methods:count()
91 return self._count;
92 end
93
94 local function new(size, on_evict)
95 size = assert(tonumber(size), "cache size must be a number");
96 size = math.floor(size);
97 assert(size > 0, "cache size must be greater than zero");
98 local data = {};
99 return setmetatable({ _data = data, _count = 0, size = size, _head = nil, _tail = nil, _on_evict = on_evict }, cache_mt);
100 end
101
91 return { 102 return {
92 new = new; 103 new = new;
93 } 104 }