Files

168 lines
5.6 KiB
Lua

-------------------------------------------------------------------------------------
-- Title: Mik's Table Recyler Object
-- Author: Mik
-- Maintainer: Athene
-- Credits:
-- Thanks to tekkub, the author of compostLib. I adapted much of his code for
-- this object.
-------------------------------------------------------------------------------------
-- Create "namespace."
MikTRO = {};
-- Set the __index property to the recycler object namespace so
-- when a new recycler object sets it metatable to the namespace
-- the recycler object inherits the functions in the namespace.
MikTRO.__index = MikTRO;
-- **********************************************************************************
-- Creates a recycler object.
-- **********************************************************************************
function MikTRO:NewRecyclerObject(maxEntries)
-- Create a table to use.
recyclerObject = {};
-- Create a table to hold the cache entries and set its max permanent size.
recyclerObject.PrimaryCache = {};
recyclerObject.PrimaryCacheSize = 0;
recyclerObject.MaxEntries = maxEntries;
-- Create some variables to hold stats.
recyclerObject.NumNew = 0;
recyclerObject.NumRecycled = 0;
recyclerObject.NumErased = 0;
recyclerObject.NumReclaimed = 0;
recyclerObject.AmountMemFreed = 0;
-- Create a table to hold overflow entries. If more tables are reclaimed
-- than the size of the max primary cache can hold, they will be reclaimed
-- into the overflow cache which is a weak table. This allows for spikes
-- in cache usage to still be optimized while not preventing garbage
-- collection on the extra data once there are no other references to them.
recyclerObject.OverflowCache = {};
setmetatable(recyclerObject.OverflowCache, {__mode = "v"});
-- Set the meta table for the cache object to the table recycler
-- obect's namespace so the cache object inherits the functions of
-- table recycler object.
setmetatable(recyclerObject, self);
-- Return the recycler object.
return recyclerObject;
end
-- **********************************************************************************
-- Removes a table from the cache and returns it. If there are no tables available
-- in the cache a new one is returned.
-- **********************************************************************************
function MikTRO:AcquireTable()
-- Check if there are any tables available in the primary cache and if so
-- return one.
if (self.PrimaryCacheSize > 0) then
-- Increment the number of recycled tables.
self.NumRecycled = self.NumRecycled + 1;
self.PrimaryCacheSize = self.PrimaryCacheSize - 1;
return table.remove(self.PrimaryCache);
-- Check if there are any tables available in the overflow cache and if so
-- return one.
elseif self:TablesInOverflow() then
-- Increment the number of recycled tables.
self.NumRecycled = self.NumRecycled + 1;
-- Loop through the tables in the overflow and return one.
for i in pairs(self.OverflowCache) do
return table.remove(self.OverflowCache, i);
end
-- No tables available so return a new one.
else
-- Increment the number of new tables created.
self.NumNew = self.NumNew + 1;
return {};
end
end
-- **********************************************************************************
-- Reclaims a table into the cache.
-- **********************************************************************************
function MikTRO:ReclaimTable(t)
-- Check if the passed value isn't valid.
if (type(t) ~= "table") then
return;
end
-- Erase the passed table.
self:EraseTable(t);
-- Check if the primary cache is already full.
if (self.PrimaryCacheSize >= self.MaxEntries) then
-- Insert the table into the overflow cache.
table.insert(self.OverflowCache, t);
else
-- Insert the table into the primary cache.
table.insert(self.PrimaryCache, t);
self.PrimaryCacheSize = self.PrimaryCacheSize + 1;
end
-- Increment the number of reclaimed tables.
self.NumReclaimed = self.NumReclaimed + 1;
end
-- **********************************************************************************
-- Erases the passed table. Subtables are NOT erased.
-- **********************************************************************************
function MikTRO:EraseTable(t)
-- Check if the passed value isn't valid.
if (type(t) ~= "table") then
return;
end
-- Loop through all the keys in the table and clear it.
for key in pairs(t) do
t[key] = nil;
end
-- Set the length of the table to 0.
table.setn(t, 0);
-- Increment the number of tables erased.
self.NumErased = self.NumErased + 1;
end
-- **********************************************************************************
-- Prints stats.
-- **********************************************************************************
function MikTRO:PrintStats()
local overflowSize = 0;
for i in pairs(self.OverflowCache) do
overflowSize = overflowSize + 1;
end
DEFAULT_CHAT_FRAME:AddMessage(string.format(
"|cff00ff00New Tables: %d|r |cffffff00Recycled Tables: %d|r |cff00ffffCached Tables: %d|r |cffff0000Overflow Tables: %d|r |cff888888Erased Tables: %d|r |cffff00ffMemory Saved: %d KiB|r |cffff0088Tables Lost to GC: %d",
self.NumNew,
self.NumRecycled,
self.PrimaryCacheSize,
overflowSize,
self.NumErased,
self.AmountMemFreed + ((32/1024) * self.NumRecycled),
self.NumReclaimed - self.NumRecycled - self.PrimaryCacheSize));
end
-- **********************************************************************************
-- Checks if there are any tables in the overflow cache.
-- **********************************************************************************
function MikTRO:TablesInOverflow()
return next(self.OverflowCache) ~= nil;
end