Software /
code /
prosody
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 } |