util.cache: Make sure cache size is specified as an integer
[prosody.git] / util / cache.lua
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
12 local function _remove(list, m)
13         if m.prev then
14                 m.prev.next = m.next;
15         end
16         if m.next then
17                 m.next.prev = m.prev;
18         end
19         if list.tail == m then
20                 list.tail = m.prev;
21         end
22         if list.head == m then
23                 list.head = m.next;
24         end
25         list.count = list.count - 1;
26 end
27
28 local function _insert(list, m)
29         if list.head then
30                 list.head.prev = m;
31         end
32         m.prev, m.next = nil, list.head;
33         list.head = m;
34         if not list.tail then
35                 list.tail = m;
36         end
37         list.count = list.count + 1;
38 end
39
40 function cache_methods:set(k, v)
41         local m = self.data[k];
42         if m then
43                 -- Key already exists
44                 if v ~= nil then
45                         -- Bump to head of list
46                         _remove(self, m);
47                         _insert(self, m);
48                         m.value = v;
49                 else
50                         -- Remove from list
51                         _remove(self, m);
52                         self.data[k] = nil;
53                 end
54                 return;
55         end
56         -- New key
57         if v == nil then
58                 return;
59         end
60         -- Check whether we need to remove oldest k/v
61         if self.count == self.size then
62                 self.data[self.tail.key] = nil;
63                 _remove(self, self.tail);
64         end
65
66         m = { key = k, value = v, prev = nil, next = nil };
67         self.data[k] = m;
68         _insert(self, m);
69 end
70
71 function cache_methods:get(k)
72         local m = self.data[k];
73         if m then
74                 return m.value;
75         end
76         return nil;
77 end
78
79 function cache_methods:items()
80         local m = self.head;
81         return function ()
82                 if not m then
83                         return;
84                 end
85                 local k, v = m.key, m.value;
86                 m = m.next;
87                 return k, v;
88         end
89 end
90
91 return {
92         new = new;
93 }