iriel.org

Navigation

> 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