vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | |
2 | --[[ |
||
3 | Name: Compost-2.0 |
||
4 | Revision: $Rev: 17406 $ |
||
5 | Author: Tekkub Stoutwrithe (tekkub@gmail.com) |
||
6 | Website: http://wiki.wowace.com/index.php/CompostLib |
||
7 | Documentation: http://wiki.wowace.com/index.php/Compost-2.0_API_Documentation |
||
8 | SVN: svn://svn.wowace.com/root/trunk/CompostLib/Compost-2.0 |
||
9 | Description: Recycle tables to reduce garbage generation |
||
10 | Dependencies: AceLibrary |
||
11 | ]] |
||
12 | |||
13 | local vmajor, vminor = "Compost-2.0", "$Revision: 17406 $" |
||
14 | |||
15 | if not AceLibrary then error(vmajor .. " requires AceLibrary.") end |
||
16 | if not AceLibrary:IsNewVersion(vmajor, vminor) then return end |
||
17 | |||
18 | local lua51 = loadstring("return function(...) return ... end") and true or false |
||
19 | local lib = {} |
||
20 | |||
21 | |||
22 | -- Activate a new instance of this library |
||
23 | local function activate(self, oldLib, oldDeactivate) |
||
24 | if oldLib then -- if upgrading |
||
25 | self.var, self.k = oldLib.var, oldLib.k |
||
26 | else |
||
27 | self.k = { -- Constants go here |
||
28 | maxcache = 10, -- I think this is a good number, I'll change it later if necessary |
||
29 | } |
||
30 | self.var = { -- "Local" variables go here |
||
31 | cache = {}, |
||
32 | secondarycache = {}, |
||
33 | } |
||
34 | |||
35 | -- This makes the secondary cache table a weak table, any values in it will be reclaimed |
||
36 | -- during a GC if there are no other references to them |
||
37 | setmetatable(self.var.secondarycache, {__mode = "v"}) |
||
38 | end |
||
39 | if not self.var.tablechecks then |
||
40 | self.var.tablechecks = {} |
||
41 | setmetatable(self.var.tablechecks, {__mode = "kv"}) |
||
42 | for i,v in ipairs(self.var.cache) do self.var.tablechecks[v] = true end |
||
43 | for i,v in ipairs(self.var.secondarycache) do self.var.tablechecks[v] = true end |
||
44 | end |
||
45 | if oldDeactivate then oldDeactivate(oldLib) end |
||
46 | end |
||
47 | |||
48 | |||
49 | -- Removes an empty table from the cache and returns it |
||
50 | -- or generates a new table if none available |
||
51 | function lib:GetTable() |
||
52 | if lua51 or self.var.disabled then return {} end |
||
53 | |||
54 | if table.getn(self.var.cache) > 0 then |
||
55 | for i in pairs(self.var.cache) do |
||
56 | local t = table.remove(self.var.cache, i) |
||
57 | self.var.tablechecks[t] = nil |
||
58 | if next(t) then -- Table has been modified, someone holds a ref still, discard it |
||
59 | error("Someone is modifying tables reclaimed by Compost!") |
||
60 | self:IncDec("numdiscarded", 1) |
||
61 | else -- It's clean, we think... return it. |
||
62 | self:IncDec("totn", -1) |
||
63 | self:IncDec("numrecycled", 1) |
||
64 | return t |
||
65 | end |
||
66 | end |
||
67 | end |
||
68 | |||
69 | if next(self.var.secondarycache) then |
||
70 | for i in pairs(self.var.secondarycache) do |
||
71 | local t = table.remove(self.var.secondarycache, i) |
||
72 | self.var.tablechecks[t] = nil |
||
73 | if next(t) then -- Table has been modified, someone holds a ref still, discard it |
||
74 | error("Someone is modifying tables reclaimed by Compost!") |
||
75 | self:IncDec("numdiscarded", 1) |
||
76 | else -- It's clean, we think... return it. |
||
77 | self:IncDec("totn", -1) |
||
78 | self:IncDec("numrecycled", 1) |
||
79 | return t |
||
80 | end |
||
81 | end |
||
82 | end |
||
83 | |||
84 | self:IncDec("numnew", 1) |
||
85 | return {} |
||
86 | end |
||
87 | |||
88 | |||
89 | -- Returns a table, populated with any variables passed |
||
90 | -- basically: return {a1, a2, ... a20} |
||
91 | if lua51 then |
||
92 | --[[ |
||
93 | function lib:Acquire(...) |
||
94 | return self:Populate({}, ...) |
||
95 | end |
||
96 | ]] |
||
97 | lib.Acquire = loadstring([[return function(self, ...) |
||
98 | return self:Populate({}, ...) |
||
99 | end]])() |
||
100 | else |
||
101 | function lib:Acquire(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
102 | local t = self:GetTable() |
||
103 | return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
104 | end |
||
105 | end |
||
106 | |||
107 | |||
108 | -- Acquires a table and fills it with values, hash style |
||
109 | -- basically: return {k1 = v1, k2 = v2, ... k10 = v10} |
||
110 | if lua51 then |
||
111 | --[[ |
||
112 | function lib:AcquireHash(...) |
||
113 | return self:PopulateHash({}, ...) |
||
114 | end |
||
115 | ]] |
||
116 | lib.AcquireHash = loadstring([[return function(self, ...) |
||
117 | return self:PopulateHash({}, ...) |
||
118 | end]])() |
||
119 | else |
||
120 | function lib:AcquireHash(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
121 | local t = self:GetTable() |
||
122 | return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
123 | end |
||
124 | end |
||
125 | |||
126 | |||
127 | -- Erases the table passed, fills it with the args passed, and returns it |
||
128 | -- Essentially the same as doing Reclaim then Acquire, except the same table is reused |
||
129 | if lua51 then |
||
130 | --[[ |
||
131 | function lib:Recycle(t, ...) |
||
132 | t = self:Erase(t) |
||
133 | return self:Populate(t, ...) |
||
134 | end |
||
135 | ]] |
||
136 | lib.Recycle = loadstring([[return function(self, t, ...) |
||
137 | t = self:Erase(t) |
||
138 | return self:Populate(t, ...) |
||
139 | end]])() |
||
140 | else |
||
141 | function lib:Recycle(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
142 | t = self:Erase(t) |
||
143 | return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
144 | end |
||
145 | end |
||
146 | |||
147 | |||
148 | -- Erases the table passed, fills it with the args passed, and returns it |
||
149 | -- Essentially the same as doing Reclaim then AcquireHash, except the same table is reused |
||
150 | if lua51 then |
||
151 | --[[ |
||
152 | function lib:RecycleHash(t, ...) |
||
153 | t = self:Erase(t) |
||
154 | return self:PopulateHash(t, ...) |
||
155 | end |
||
156 | ]] |
||
157 | lib.RecycleHash = loadstring([[return function(self, t, ...) |
||
158 | t = self:Erase(t) |
||
159 | return self:PopulateHash(t, ...) |
||
160 | end]])() |
||
161 | else |
||
162 | function lib:RecycleHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
163 | t = self:Erase(t) |
||
164 | return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
165 | end |
||
166 | end |
||
167 | |||
168 | -- Returns a table to the cache |
||
169 | -- All tables referenced inside the passed table will be reclaimed also |
||
170 | -- If a depth is passed, Reclaim will call itsself recursivly |
||
171 | -- to reclaim all tables contained in t to the depth specified |
||
172 | if lua51 then |
||
173 | function lib:Reclaim() end |
||
174 | else |
||
175 | function lib:Reclaim(t, depth) |
||
176 | if type(t) ~= "table" or self.var.disabled then return end |
||
177 | self:assert(not self.var.tablechecks[t], "Cannot reclaim a table twice") |
||
178 | |||
179 | if not self:ItemsInSecondaryCache() then self.var.totn = table.getn(self.var.cache) end |
||
180 | |||
181 | if depth and depth > 0 then |
||
182 | for i in pairs(t) do |
||
183 | if type(t[i]) == "table" then self:Reclaim(t[i], depth - 1) end |
||
184 | end |
||
185 | end |
||
186 | self:Erase(t) |
||
187 | if self.k.maxcache and table.getn(self.var.cache) >= self.k.maxcache then |
||
188 | table.insert(self.var.secondarycache, t) |
||
189 | else |
||
190 | table.insert(self.var.cache, t) |
||
191 | end |
||
192 | self:IncDec("numreclaim", 1) |
||
193 | self:IncDec("totn", 1) |
||
194 | self.var.maxn = math.max(self.var.maxn or 0, self.var.totn) |
||
195 | self.var.tablechecks[t] = true |
||
196 | end |
||
197 | end |
||
198 | |||
199 | -- Reclaims multiple tables, can take 10 recursive sets or 20 non-recursives, |
||
200 | -- or any combination of the two. Pass args in the following manner: |
||
201 | -- table1, depth1, tabl2, depth2, table3, table4, table5, depth5, ... |
||
202 | if lua51 then |
||
203 | function lib:ReclaimMulti() end |
||
204 | else |
||
205 | function lib:ReclaimMulti(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
206 | if not a1 then return end |
||
207 | if type(a2) == "number" then |
||
208 | self:Reclaim(a1, a2) |
||
209 | self:ReclaimMulti(a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
210 | else |
||
211 | self:Reclaim(a1) |
||
212 | self:ReclaimMulti(a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
213 | end |
||
214 | end |
||
215 | end |
||
216 | |||
217 | -- Erases the table passed, nothing more nothing less :) |
||
218 | -- Tables referenced inside the passed table are NOT erased |
||
219 | if lua51 then |
||
220 | function lib:Erase() return {} end |
||
221 | else |
||
222 | function lib:Erase(t) |
||
223 | if type(t) ~= "table" then return end |
||
224 | if self.var.disabled then return {} end |
||
225 | local mem = gcinfo() |
||
226 | setmetatable(t, nil) |
||
227 | for i in pairs(t) do |
||
228 | t[i] = nil |
||
229 | end |
||
230 | t.reset = 1 |
||
231 | t.reset = nil |
||
232 | table.setn(t, 0) |
||
233 | self:IncDec("memfreed", math.abs(gcinfo() - mem)) |
||
234 | self:IncDec("numerased", 1) |
||
235 | return t |
||
236 | end |
||
237 | end |
||
238 | |||
239 | -- Fills the table passed with the args passed |
||
240 | if lua51 then |
||
241 | --[[ |
||
242 | function lib:Populate(t, a, ...) |
||
243 | if not t then return |
||
244 | elseif a ~= nil then |
||
245 | table.insert(t, a) |
||
246 | return self:Populate(t, ...) |
||
247 | else return t end |
||
248 | end |
||
249 | ]] |
||
250 | lib.Populate = loadstring([[return function(self, t, a, ...) |
||
251 | if not t then return |
||
252 | elseif a ~= nil then |
||
253 | table.insert(t, a) |
||
254 | return self:Populate(t, ...) |
||
255 | else return t end |
||
256 | end]])() |
||
257 | else |
||
258 | function lib:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
259 | if not t then return end |
||
260 | if a1 ~= nil then table.insert(t, a1) end |
||
261 | if a2 ~= nil then table.insert(t, a2) end |
||
262 | if a3 ~= nil then table.insert(t, a3) end |
||
263 | if a4 ~= nil then table.insert(t, a4) end |
||
264 | if a5 ~= nil then table.insert(t, a5) end |
||
265 | if a6 ~= nil then table.insert(t, a6) end |
||
266 | if a7 ~= nil then table.insert(t, a7) end |
||
267 | if a8 ~= nil then table.insert(t, a8) end |
||
268 | if a9 ~= nil then table.insert(t, a9) end |
||
269 | if a10 ~= nil then table.insert(t, a10) end |
||
270 | if a11 ~= nil then table.insert(t, a11) end |
||
271 | if a12 ~= nil then table.insert(t, a12) end |
||
272 | if a13 ~= nil then table.insert(t, a13) end |
||
273 | if a14 ~= nil then table.insert(t, a14) end |
||
274 | if a15 ~= nil then table.insert(t, a15) end |
||
275 | if a16 ~= nil then table.insert(t, a16) end |
||
276 | if a17 ~= nil then table.insert(t, a17) end |
||
277 | if a18 ~= nil then table.insert(t, a18) end |
||
278 | if a19 ~= nil then table.insert(t, a19) end |
||
279 | if a20 ~= nil then table.insert(t, a20) end |
||
280 | return t |
||
281 | end |
||
282 | end |
||
283 | |||
284 | -- Same as Populate, but takes 10 key-value pairs instead |
||
285 | if lua51 then |
||
286 | --[[ |
||
287 | function lib:PopulateHash(t, k, v, ...) |
||
288 | if not t then return |
||
289 | elseif k ~= nil then |
||
290 | t[k] = v |
||
291 | return self:PopulateHash(t, ...) |
||
292 | else return t end |
||
293 | end |
||
294 | ]] |
||
295 | lib.PopulateHash = loadstring([[return function(self, t, k, v, ...) |
||
296 | if not t then return |
||
297 | elseif k ~= nil then |
||
298 | t[k] = v |
||
299 | return self:PopulateHash(t, ...) |
||
300 | else return t end |
||
301 | end]])() |
||
302 | else |
||
303 | function lib:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
304 | if not t then return end |
||
305 | if k1 ~= nil then t[k1] = v1 end |
||
306 | if k2 ~= nil then t[k2] = v2 end |
||
307 | if k3 ~= nil then t[k3] = v3 end |
||
308 | if k4 ~= nil then t[k4] = v4 end |
||
309 | if k5 ~= nil then t[k5] = v5 end |
||
310 | if k6 ~= nil then t[k6] = v6 end |
||
311 | if k7 ~= nil then t[k7] = v7 end |
||
312 | if k8 ~= nil then t[k8] = v8 end |
||
313 | if k9 ~= nil then t[k9] = v9 end |
||
314 | if k10 ~= nil then t[k10] = v10 end |
||
315 | return t |
||
316 | end |
||
317 | end |
||
318 | |||
319 | function lib:IncDec(variable, diff) |
||
320 | self.var[variable] = (self.var[variable] or 0) + diff |
||
321 | end |
||
322 | |||
323 | |||
324 | function lib:ItemsInSecondaryCache() |
||
325 | for i in pairs(self.var.secondarycache) do return true end |
||
326 | end |
||
327 | |||
328 | |||
329 | function lib:GetSecondaryCacheSize() |
||
330 | local n = 0 |
||
331 | for i in pairs(self.var.secondarycache) do n = n + 1 end |
||
332 | return n |
||
333 | end |
||
334 | |||
335 | |||
336 | -- Prints out statistics on table recycling |
||
337 | -- /script CompostLib:GetInstance("compost-1"):Stats() |
||
338 | function lib:Stats() |
||
339 | if self.var.disabled then ChatFrame1:AddMessage("CompostLib is disabled!") |
||
340 | else ChatFrame1:AddMessage( |
||
341 | string.format( |
||
342 | "|cff00ff00New: %d|r | |cffffff00Recycled: %d|r | |cff00ffffMain: %d|r | |cffff0000Secondary: %d|r | |cffff8800Max %d|r | |cff888888Erases: %d|r | |cffff00ffMem Saved: %d KiB|r | |cffff0088Lost to GC: %d", |
||
343 | self.var.numnew or 0, |
||
344 | self.var.numrecycled or 0, |
||
345 | table.getn(self.var.cache), |
||
346 | self:GetSecondaryCacheSize(), |
||
347 | self.var.maxn or 0, |
||
348 | (self.var.numerased or 0) - (self.var.numreclaim or 0), |
||
349 | (self.var.memfreed or 0) + 32/1024*(self.var.numrecycled or 0), |
||
350 | (self.var.numreclaim or 0) - (self.var.numrecycled or 0) - table.getn(self.var.cache))) |
||
351 | end |
||
352 | end |
||
353 | |||
354 | setmetatable(lib, { __call = lib.Acquire }) |
||
355 | |||
356 | -------------------------------- |
||
357 | -- Load this bitch! -- |
||
358 | -------------------------------- |
||
359 | AceLibrary:Register(lib, vmajor, vminor, activate) |
||
360 | lib = nil |