> Sub-Frame Cache
Subframe caching for addons
A commonly occuring idiom in some WoW addons is to reference a frame's subframes by name. While this is quite simple, it's computationally rather expensive, especially when repeated many times.
This code implements a friendly cache of frame identites by name OR by object, and caches subframe accesses by name suffix.
subframecache.lua
-- Some code to do subframe caching for CTRA (And others)
-- Author; iriel@vigilance-committee.org
--
-- Each subframe cache is a 2 level cache, the first level is indexed with a
-- Frame or FrameName, and returns the second level cache for that object
-- the second level cache is indexed with a sub-name, and returns the frame
-- for that subname.
--
-- So.
-- FCache = CreateSubframeCache();
--
-- FCache["CT_RAMember1"] -- Returns subcache for CT_RAMember1
-- FCache[CT_RAMember1] -- Also returns subcache for CT_RAMember1
--
-- FCache[CT_RAMember1].HPBar -- returns the CT_RAMember1HPBar frame
-- FCache[CT_RAMember1].MPBar -- returns the CT_RAMember1MPBar frame
--
-- If you have to go multiple levels deep, then you need to do 2 sets of
-- calls:
--
-- local cast = FCache[CT_RAMember1].Cast
-- FCache[cast].Frame -- returns the CT_RAMember1CastFrame frame
--
-- If you want to really cut down on calls, and are accessing a specific
-- subcache a lot, do soemthing like this:
--
-- local frameC = FCache[CT_RAMember1];
--
-- frameC.HPBar -- CT_RAMember1HPBar
-- frameC.MPBar -- CT_RAMember1MPBar
--
-- etc
--
-- Ideally the frame cache would be a local variable to your code, so
-- either create one for each file, or make it a 'locally bound global'
-- like this:
--
-- GlobalSubframeCache = CreateSubframeCache();
-- local LocalSubframeCache = GlobalSubframeCache;
--
-- Version history:
-- v3 - Rearranged order, fixed more typos
-- v2 - Corrected some typos, cleaned up name->frame lookup
-- v1 - First version
-- Inner cache metatable
local subMeta = {
-- Given a name, append it to the parent frame name, and then return
-- the result (cache it if it's found)
__index = function(t, name)
local tn = type(name);
if (tn == "string" or tn == "number") then
local realName = t._frameName .. name;
local realFrame = getglobal(realName);
if (realFrame) then
t[name] = realFrame;
end
return realFrame;
end
end
};
local topMeta = {
-- Given a frame or a frame name, create (or return) the subcache
-- for that frame.
__index = function(t, frame)
local tf = type(frame);
if (tf == "string") then
-- If we're passed a frame name, look up the frame behind
-- it and if it's found, get its subcache
local realFrame = getglobal(frame);
-- Prevent infinite looping
if (type(realFrame)=="table") then
local ret = t[realFrame];
if (ret) then
t[frame] = ret;
end
return ret;
end
elseif (tf == "table") then
-- Must create a new caching subtable if frame is an
-- actual Frame.
local gn = frame.GetName;
if (gn) then
local ret = {};
ret._frame = frame;
ret._frameName = gn(frame);
setmetatable(ret, subMeta);
t[frame] = ret;
return ret;
end
end
end
}
-- Create a fresh subframe cache and return it.
function CreateSubframeCache()
local ret = {};
setmetatable(ret, topMeta);
return ret;
end
