--------------------------------------------------------------------------- -- Embedded Library Registration Stub -- Written by Iriel -- Version 0.1 - 2006-03-05 -- Modified by Tekkub --------------------------------------------------------------------------- -- YOU DON'T NEED TO TOUCH ANYTHING IN THIS BLOCK OF CODE --------------------------------------------------------------------------- if not EmbedLibStub then EmbedLibStub = {} -- Instance replacement method, replace contents of old with that of new function EmbedLibStub:ReplaceInstance(old, new) for k,v in pairs(old) do old[k]=nil end for k,v in pairs(new) do old[k]=v end end -- Get a new copy of the stub function EmbedLibStub:NewStub(name) local newStub = {} self:ReplaceInstance(newStub, self) newStub.libName = name newStub.lastVersion = '' newStub.versions = {} return newStub end -- Get instance version function EmbedLibStub:NeedsUpgraded(vmajor, vminor) local versionData = self.versions[vmajor] if not versionData or versionData.minor < vminor then return true end end -- Get instance version function EmbedLibStub:GetInstance(version) if not version then version = self.lastVersion end local versionData = self.versions[version] if not versionData then print(string.format("<%s> Cannot find library version: %s", self.libName, version or "")) return end return versionData.instance end -- Register new instance function EmbedLibStub:Register(newInstance) local version,minor = newInstance:GetLibraryVersion() self.lastVersion = version local versionData = self.versions[version] if not versionData then -- This one is new! versionData = { instance = newInstance, minor = minor, old = {}, } self.versions[version] = versionData newInstance:LibActivate(self) return newInstance end -- This is an update local oldInstance = versionData.instance local oldList = versionData.old versionData.instance = newInstance versionData.minor = minor local skipCopy = newInstance:LibActivate(self, oldInstance, oldList) table.insert(oldList, oldInstance) if not skipCopy then for i, old in ipairs(oldList) do self:ReplaceInstance(old, newInstance) end end return newInstance end end ---------------------------------- -- Library Definition -- ---------------------------------- local vmajor, vminor = "compost-1", 1 local libvarname = "CompostLib" local usedebug = false --------------------------------------------------------------------------- -- This code is the Library's management code -- You don't need to change anything here --------------------------------------------------------------------------- local libobj = getglobal(libvarname) if not libobj then libobj = EmbedLibStub:NewStub(libvarname) setglobal(libvarname, libobj) end if libobj:NeedsUpgraded(vmajor, vminor) then local lib = {} -- Return the library's current version function lib:GetLibraryVersion() return vmajor, vminor end -- Activate a new instance of this library function lib:LibActivate(stub, oldLib, oldList) local maj, min = self:GetLibraryVersion() if usedebug then print(string.format("<%s> Activating version %s - %d", libvarname, maj, min)) end if oldLib then local omaj, omin = oldLib:GetLibraryVersion() if usedebug then print(string.format("<%s> Replacing old version %s - %d", libvarname, omaj, omin)) end self.var, self.k = oldLib.var, oldLib.k else self.k = { -- Constants go here maxcache = 10, -- I think this is a good number, I'll change it later if necessary } self.var = { -- "Local" variables go here cache = {}, secondarycache = {}, } -- This makes the secondary cache table a weak table, any values in it will be reclaimed -- during a GC if there are no other references to them setmetatable(self.var.secondarycache, {__mode = "v"}) end -- nil return makes stub do object copy end -- Removes an empty table from the cache and returns it -- or generates a new table if none available function lib:Acquire() if self.var.disabled then return {} end if table.getn(self.var.cache) > 0 then self:IncDec("totn", -1) self:IncDec("numr", 1) local t = self.var.cache[1] table.remove(self.var.cache, 1) return t elseif self:ItemsInSecondaryCache() then self:IncDec("totn", -1) self:IncDec("numr", 1) for i in pairs(self.var.secondarycache) do local t = self.var.secondarycache[i] table.remove(self.var.secondarycache, i) return t end else self:IncDec("numn", 1) return {} end end -- Returns a table to the cache -- All tables referenced inside the passed table will be reclaimed also -- If depth is passed any tables referenced in t will also be reclaimed ***USE THIS CAREFULLY*** function lib:Reclaim(t, depth) if type(t) ~= "table" or self.var.disabled then return end if not self:ItemsInSecondaryCache() then self.var.totn = table.getn(self.var.cache) end if depth and depth > 0 then for i in pairs(t) do if type(t[i]) == "table" then self:Reclaim(t[i], depth - 1) end end end self:Erase(t) if self.var.maxcache and table.getn(self.var.cache) >= self.var.maxcache then table.insert(self.var.secondarycache, t) else table.insert(self.var.cache, t) end self:IncDec("totn", 1) self.var.maxn = math.max(self.var.maxn or 0, self.var.totn) end -- Erases the table passed, nothing more nothing less :) -- Tables referenced inside the passed table are NOT erased function lib:Erase(t) if type(t) ~= "table" then return end if self.var.disabled then return {} end local mem = gcinfo() for i in pairs(t) do t[i] = nil end t.reset = 1 t.reset = nil table.setn(t, 0) self:IncDec("memf", math.abs(gcinfo() - mem)) self:IncDec("nume", 1) return t end function lib:IncDec(variable, diff) self.var[variable] = (self.var[variable] or 0) + diff end function lib:ItemsInSecondaryCache() for i in pairs(self.var.secondarycache) do return true end end function lib:GetSecondaryCacheSize() local n = 0 for i in pairs(self.var.secondarycache) do n = n + 1 end return n end -- Prints out statistics on table recycling -- /script CompostLib:GetInstance("compost-1"):Stats() function lib:Stats() if self.var.disabled then ChatFrame1:AddMessage("CompostLib is disabled!") else ChatFrame1:AddMessage( string.format( "|cff00ff00New: %d|r | |cffffff00Recycled: %d|r | |cff00ffffSaved: %d|r | |cffff0000Secondary: %d|r | |cffff8800Max %d|r | |cff888888Erases: %d|r | |cffff00ffMem Freed: %d KiB", self.var.numn or 0, self.var.numr or 0, table.getn(self.var.cache), self:GetSecondaryCacheSize(), self.var.maxn or 0, (self.var.nume or 0) - (self.var.numr or 0) - table.getn(self.var.cache) - self:GetSecondaryCacheSize(), (self.var.memf or 0) + 32/1024*(self.var.numr or 0))) end end -------------------------------- -- Load this bitch! -- -------------------------------- libobj:Register(lib) end