vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | |
2 | ------------------------------------------------------------------- |
||
3 | --***************************************************************-- |
||
4 | --** All authors using this library please see the wiki: **-- |
||
5 | --** http://wiki.wowace.com/index.php/Compost_Embedded_Library **-- |
||
6 | --***************************************************************-- |
||
7 | ------------------------------------------------------------------- |
||
8 | |||
9 | local vmajor, vminor = "compost-1", tonumber(string.sub("$Revision: 6648 $", 12, -3)) |
||
10 | local stubvarname = "TekLibStub" |
||
11 | local libvarname = "CompostLib" |
||
12 | local usedebug = false |
||
13 | |||
14 | |||
15 | local libobj = getglobal(libvarname) |
||
16 | if libobj and not libobj:NeedsUpgraded(vmajor, vminor) then return end |
||
17 | |||
18 | |||
19 | --------------------------------------------------------------------------- |
||
20 | -- Based off Embedded Library template |
||
21 | -- Written by Iriel <iriel@vigilance-committee.org> |
||
22 | -- Version 0.1 - 2006-03-05 |
||
23 | -- Modified by Tekkub <tekkub@gmail.com> |
||
24 | --------------------------------------------------------------------------- |
||
25 | |||
26 | local stubobj = getglobal(stubvarname) |
||
27 | if not stubobj then |
||
28 | stubobj = {} |
||
29 | setglobal(stubvarname, stubobj) |
||
30 | |||
31 | |||
32 | -- Instance replacement method, replace contents of old with that of new |
||
33 | function stubobj:ReplaceInstance(old, new) |
||
34 | for k,v in pairs(old) do old[k]=nil end |
||
35 | for k,v in pairs(new) do old[k]=v end |
||
36 | end |
||
37 | |||
38 | |||
39 | -- Get a new copy of the stub |
||
40 | function stubobj:NewStub(name) |
||
41 | local newStub = {} |
||
42 | self:ReplaceInstance(newStub, self) |
||
43 | newStub.libName = name |
||
44 | newStub.lastVersion = '' |
||
45 | newStub.versions = {} |
||
46 | return newStub |
||
47 | end |
||
48 | |||
49 | |||
50 | -- Get instance version |
||
51 | function stubobj:NeedsUpgraded(vmajor, vminor) |
||
52 | local versionData = self.versions[vmajor] |
||
53 | if not versionData or versionData.minor < vminor then return true end |
||
54 | end |
||
55 | |||
56 | |||
57 | -- Get instance version |
||
58 | function stubobj:GetInstance(version) |
||
59 | if not version then version = self.lastVersion end |
||
60 | local versionData = self.versions[version] |
||
61 | if not versionData then print(string.format("<%s> Cannot find library version: %s", self.libName, version or "")) return end |
||
62 | return versionData.instance |
||
63 | end |
||
64 | |||
65 | |||
66 | -- Register new instance |
||
67 | function stubobj:Register(newInstance) |
||
68 | local version,minor = newInstance:GetLibraryVersion() |
||
69 | self.lastVersion = version |
||
70 | local versionData = self.versions[version] |
||
71 | if not versionData then |
||
72 | -- This one is new! |
||
73 | versionData = { |
||
74 | instance = newInstance, |
||
75 | minor = minor, |
||
76 | old = {}, |
||
77 | } |
||
78 | self.versions[version] = versionData |
||
79 | newInstance:LibActivate(self) |
||
80 | return newInstance |
||
81 | end |
||
82 | -- This is an update |
||
83 | local oldInstance = versionData.instance |
||
84 | local oldList = versionData.old |
||
85 | versionData.instance = newInstance |
||
86 | versionData.minor = minor |
||
87 | local skipCopy = newInstance:LibActivate(self, oldInstance, oldList) |
||
88 | table.insert(oldList, oldInstance) |
||
89 | if not skipCopy then |
||
90 | for i, old in ipairs(oldList) do self:ReplaceInstance(old, newInstance) end |
||
91 | end |
||
92 | return newInstance |
||
93 | end |
||
94 | end |
||
95 | |||
96 | |||
97 | -------------------------------- |
||
98 | -- Embedded Library -- |
||
99 | -------------------------------- |
||
100 | |||
101 | if not libobj then |
||
102 | libobj = stubobj:NewStub(libvarname) |
||
103 | setglobal(libvarname, libobj) |
||
104 | end |
||
105 | |||
106 | local lib = {} |
||
107 | |||
108 | |||
109 | -- Return the library's current version |
||
110 | function lib:GetLibraryVersion() |
||
111 | return vmajor, vminor |
||
112 | end |
||
113 | |||
114 | |||
115 | -- Activate a new instance of this library |
||
116 | function lib:LibActivate(stub, oldLib, oldList) |
||
117 | local maj, min = self:GetLibraryVersion() |
||
118 | if usedebug then print(string.format("<%s> Activating version %s - %d", libvarname, maj, min)) end |
||
119 | |||
120 | if oldLib then |
||
121 | local omaj, omin = oldLib:GetLibraryVersion() |
||
122 | if usedebug then print(string.format("<%s> Replacing old version %s - %d", libvarname, omaj, omin)) end |
||
123 | self.var, self.k = oldLib.var, oldLib.k |
||
124 | else |
||
125 | self.k = { -- Constants go here |
||
126 | maxcache = 10, -- I think this is a good number, I'll change it later if necessary |
||
127 | } |
||
128 | self.var = { -- "Local" variables go here |
||
129 | cache = {}, |
||
130 | secondarycache = {}, |
||
131 | } |
||
132 | |||
133 | -- This makes the secondary cache table a weak table, any values in it will be reclaimed |
||
134 | -- during a GC if there are no other references to them |
||
135 | setmetatable(self.var.secondarycache, {__mode = "v"}) |
||
136 | end |
||
137 | -- nil return makes stub do object copy |
||
138 | end |
||
139 | |||
140 | |||
141 | -- Removes an empty table from the cache and returns it |
||
142 | -- or generates a new table if none available |
||
143 | function lib:GetTable() |
||
144 | if self.var.disabled then return {} end |
||
145 | if table.getn(self.var.cache) > 0 then |
||
146 | self:IncDec("totn", -1) |
||
147 | self:IncDec("numrecycled", 1) |
||
148 | return table.remove(self.var.cache) |
||
149 | elseif self:ItemsInSecondaryCache() then |
||
150 | self:IncDec("totn", -1) |
||
151 | self:IncDec("numrecycled", 1) |
||
152 | for i in pairs(self.var.secondarycache) do return table.remove(self.var.secondarycache, i) end |
||
153 | else |
||
154 | self:IncDec("numnew", 1) |
||
155 | return {} |
||
156 | end |
||
157 | end |
||
158 | |||
159 | |||
160 | -- Returns a table, populated with any variables passed |
||
161 | -- basically: return {a1, a2, ... a20} |
||
162 | function lib:Acquire(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
163 | local t = self:GetTable() |
||
164 | return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
165 | end |
||
166 | |||
167 | |||
168 | -- Acquires a table and fills it with values, hash style |
||
169 | -- basically: return {k1 = v1, k2 = v2, ... k10 = v10} |
||
170 | function lib:AcquireHash(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
171 | local t = self:GetTable() |
||
172 | return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
173 | end |
||
174 | |||
175 | |||
176 | -- Erases the table passed, fills it with the args passed, and returns it |
||
177 | -- Essentially the same as doing Reclaim then Acquire, except the same table is reused |
||
178 | function lib:Recycle(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
179 | t = self:Erase(t) |
||
180 | return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
181 | end |
||
182 | |||
183 | |||
184 | -- Erases the table passed, fills it with the args passed, and returns it |
||
185 | -- Essentially the same as doing Reclaim then AcquireHash, except the same table is reused |
||
186 | function lib:RecycleHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
187 | t = self:Erase(t) |
||
188 | return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
189 | end |
||
190 | |||
191 | |||
192 | -- Returns a table to the cache |
||
193 | -- All tables referenced inside the passed table will be reclaimed also |
||
194 | -- If a depth is passed, Reclaim will call itsself recursivly |
||
195 | -- to reclaim all tables contained in t to the depth specified |
||
196 | function lib:Reclaim(t, depth) |
||
197 | if type(t) ~= "table" or self.var.disabled then return end |
||
198 | |||
199 | if not self:ItemsInSecondaryCache() then self.var.totn = table.getn(self.var.cache) end |
||
200 | |||
201 | if depth and depth > 0 then |
||
202 | for i in pairs(t) do |
||
203 | if type(t[i]) == "table" then self:Reclaim(t[i], depth - 1) end |
||
204 | end |
||
205 | end |
||
206 | self:Erase(t) |
||
207 | if self.k.maxcache and table.getn(self.var.cache) >= self.k.maxcache then |
||
208 | table.insert(self.var.secondarycache, t) |
||
209 | else |
||
210 | table.insert(self.var.cache, t) |
||
211 | end |
||
212 | self:IncDec("numreclaim", 1) |
||
213 | self:IncDec("totn", 1) |
||
214 | self.var.maxn = math.max(self.var.maxn or 0, self.var.totn) |
||
215 | end |
||
216 | |||
217 | |||
218 | -- Reclaims multiple tables, can take 10 recursive sets or 20 non-recursives, |
||
219 | -- or any combination of the two. Pass args in the following manner: |
||
220 | -- table1, depth1, tabl2, depth2, table3, table4, table5, depth5, ... |
||
221 | function lib:ReclaimMulti(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
222 | if not a1 then return end |
||
223 | if type(a2) == "number" then |
||
224 | self:Reclaim(a1, a2) |
||
225 | self:ReclaimMulti(a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
226 | else |
||
227 | self:Reclaim(a1) |
||
228 | self:ReclaimMulti(a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
229 | end |
||
230 | end |
||
231 | |||
232 | |||
233 | -- Erases the table passed, nothing more nothing less :) |
||
234 | -- Tables referenced inside the passed table are NOT erased |
||
235 | function lib:Erase(t) |
||
236 | if type(t) ~= "table" then return end |
||
237 | if self.var.disabled then return {} end |
||
238 | local mem = gcinfo() |
||
239 | for i in pairs(t) do |
||
240 | t[i] = nil |
||
241 | end |
||
242 | t.reset = 1 |
||
243 | t.reset = nil |
||
244 | table.setn(t, 0) |
||
245 | self:IncDec("memfreed", math.abs(gcinfo() - mem)) |
||
246 | self:IncDec("numerased", 1) |
||
247 | return t |
||
248 | end |
||
249 | |||
250 | |||
251 | -- Fills the table passed with the args passed |
||
252 | function lib:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) |
||
253 | if not t then return end |
||
254 | if a1 ~= nil then table.insert(t, a1) end |
||
255 | if a2 ~= nil then table.insert(t, a2) end |
||
256 | if a3 ~= nil then table.insert(t, a3) end |
||
257 | if a4 ~= nil then table.insert(t, a4) end |
||
258 | if a5 ~= nil then table.insert(t, a5) end |
||
259 | if a6 ~= nil then table.insert(t, a6) end |
||
260 | if a7 ~= nil then table.insert(t, a7) end |
||
261 | if a8 ~= nil then table.insert(t, a8) end |
||
262 | if a9 ~= nil then table.insert(t, a9) end |
||
263 | if a10 ~= nil then table.insert(t, a10) end |
||
264 | if a11 ~= nil then table.insert(t, a11) end |
||
265 | if a12 ~= nil then table.insert(t, a12) end |
||
266 | if a13 ~= nil then table.insert(t, a13) end |
||
267 | if a14 ~= nil then table.insert(t, a14) end |
||
268 | if a15 ~= nil then table.insert(t, a15) end |
||
269 | if a16 ~= nil then table.insert(t, a16) end |
||
270 | if a17 ~= nil then table.insert(t, a17) end |
||
271 | if a18 ~= nil then table.insert(t, a18) end |
||
272 | if a19 ~= nil then table.insert(t, a19) end |
||
273 | if a20 ~= nil then table.insert(t, a20) end |
||
274 | return t |
||
275 | end |
||
276 | |||
277 | |||
278 | -- Same as Populate, but takes 10 key-value pairs instead |
||
279 | function lib:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) |
||
280 | if not t then return end |
||
281 | if k1 ~= nil then t[k1] = v1 end |
||
282 | if k2 ~= nil then t[k2] = v2 end |
||
283 | if k3 ~= nil then t[k3] = v3 end |
||
284 | if k4 ~= nil then t[k4] = v4 end |
||
285 | if k5 ~= nil then t[k5] = v5 end |
||
286 | if k6 ~= nil then t[k6] = v6 end |
||
287 | if k7 ~= nil then t[k7] = v7 end |
||
288 | if k8 ~= nil then t[k8] = v8 end |
||
289 | if k9 ~= nil then t[k9] = v9 end |
||
290 | if k10 ~= nil then t[k10] = v10 end |
||
291 | return t |
||
292 | end |
||
293 | |||
294 | |||
295 | function lib:IncDec(variable, diff) |
||
296 | self.var[variable] = (self.var[variable] or 0) + diff |
||
297 | end |
||
298 | |||
299 | |||
300 | function lib:ItemsInSecondaryCache() |
||
301 | for i in pairs(self.var.secondarycache) do return true end |
||
302 | end |
||
303 | |||
304 | |||
305 | function lib:GetSecondaryCacheSize() |
||
306 | local n = 0 |
||
307 | for i in pairs(self.var.secondarycache) do n = n + 1 end |
||
308 | return n |
||
309 | end |
||
310 | |||
311 | |||
312 | -- Prints out statistics on table recycling |
||
313 | -- /script CompostLib:GetInstance("compost-1"):Stats() |
||
314 | function lib:Stats() |
||
315 | if self.var.disabled then ChatFrame1:AddMessage("CompostLib is disabled!") |
||
316 | else ChatFrame1:AddMessage( |
||
317 | string.format( |
||
318 | "|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", |
||
319 | self.var.numnew or 0, |
||
320 | self.var.numrecycled or 0, |
||
321 | table.getn(self.var.cache), |
||
322 | self:GetSecondaryCacheSize(), |
||
323 | self.var.maxn or 0, |
||
324 | (self.var.numerased or 0) - (self.var.numreclaim or 0), |
||
325 | (self.var.memfreed or 0) + 32/1024*(self.var.numrecycled or 0), |
||
326 | (self.var.numreclaim or 0) - (self.var.numrecycled or 0) - table.getn(self.var.cache))) |
||
327 | end |
||
328 | end |
||
329 | |||
330 | |||
331 | -------------------------------- |
||
332 | -- Load this bitch! -- |
||
333 | -------------------------------- |
||
334 | libobj:Register(lib) |