Files
coa-weakauras/WeakAuras/Pools.lua
T

350 lines
9.0 KiB
Lua

if ObjectPoolMixin then
return
end
local assert = assert
local ipairs = ipairs
local next = next
local pairs = pairs
local select = select
local function Mixin(object, ...)
for i = 1, select("#", ...) do
local mixin = select(i, ...);
for k, v in pairs(mixin) do
object[k] = v;
end
end
return object;
end
local function CreateFromMixins(...)
return Mixin({}, ...)
end
local function nop()
end
ObjectPoolMixin = {};
function ObjectPoolMixin:OnLoad(creationFunc, resetterFunc)
self.creationFunc = creationFunc;
self.resetterFunc = resetterFunc;
self.activeObjects = {};
self.inactiveObjects = {};
self.numActiveObjects = 0;
end
function ObjectPoolMixin:Acquire()
local numInactiveObjects = #self.inactiveObjects;
if numInactiveObjects > 0 then
local obj = self.inactiveObjects[numInactiveObjects];
self.activeObjects[obj] = true;
self.numActiveObjects = self.numActiveObjects + 1;
self.inactiveObjects[numInactiveObjects] = nil;
return obj, false;
end
local newObj = self.creationFunc(self);
if self.resetterFunc then
self.resetterFunc(self, newObj);
end
self.activeObjects[newObj] = true;
self.numActiveObjects = self.numActiveObjects + 1;
return newObj, true;
end
function ObjectPoolMixin:Release(obj)
if self:IsActive(obj) then
self.inactiveObjects[#self.inactiveObjects + 1] = obj;
self.activeObjects[obj] = nil;
self.numActiveObjects = self.numActiveObjects - 1;
if self.resetterFunc then
self.resetterFunc(self, obj);
end
return true;
end
return false;
end
function ObjectPoolMixin:ReleaseAll()
for obj in pairs(self.activeObjects) do
self:Release(obj);
end
end
function ObjectPoolMixin:EnumerateActive()
return pairs(self.activeObjects);
end
function ObjectPoolMixin:GetNextActive(current)
return (next(self.activeObjects, current));
end
function ObjectPoolMixin:IsActive(object)
return (self.activeObjects[object] ~= nil);
end
function ObjectPoolMixin:GetNumActive()
return self.numActiveObjects;
end
function ObjectPoolMixin:EnumerateInactive()
return ipairs(self.inactiveObjects);
end
function CreateObjectPool(creationFunc, resetterFunc)
local objectPool = CreateFromMixins(ObjectPoolMixin);
objectPool:OnLoad(creationFunc, resetterFunc);
return objectPool;
end
FramePoolMixin = CreateFromMixins(ObjectPoolMixin);
local function FramePoolFactory(framePool)
return CreateFrame(framePool.frameType, nil, framePool.parent, framePool.frameTemplate);
end
local function ForbiddenFramePoolFactory(framePool)
return CreateForbiddenFrame(framePool.frameType, nil, framePool.parent, framePool.frameTemplate);
end
function FramePoolMixin:OnLoad(frameType, parent, frameTemplate, resetterFunc, forbidden)
if forbidden then
ObjectPoolMixin.OnLoad(self, ForbiddenFramePoolFactory, resetterFunc);
else
ObjectPoolMixin.OnLoad(self, FramePoolFactory, resetterFunc);
end
self.frameType = frameType;
self.parent = parent;
self.frameTemplate = frameTemplate;
end
function FramePoolMixin:GetTemplate()
return self.frameTemplate;
end
function FramePool_Hide(framePool, frame)
frame:Hide();
end
function FramePool_HideAndClearAnchors(framePool, frame)
frame:Hide();
frame:ClearAllPoints();
end
function CreateFramePool(frameType, parent, frameTemplate, resetterFunc, forbidden)
local framePool = CreateFromMixins(FramePoolMixin);
framePool:OnLoad(frameType, parent, frameTemplate, resetterFunc or FramePool_HideAndClearAnchors, forbidden);
return framePool;
end
TexturePoolMixin = CreateFromMixins(ObjectPoolMixin);
local function TexturePoolFactory(texturePool)
return texturePool.parent:CreateTexture(nil, texturePool.layer, texturePool.textureTemplate);
end
function TexturePoolMixin:OnLoad(parent, layer, textureTemplate, resetterFunc)
ObjectPoolMixin.OnLoad(self, TexturePoolFactory, resetterFunc);
self.parent = parent;
self.layer = layer;
self.textureTemplate = textureTemplate;
end
TexturePool_Hide = FramePool_Hide;
TexturePool_HideAndClearAnchors = FramePool_HideAndClearAnchors;
function CreateTexturePool(parent, layer, textureTemplate, resetterFunc)
local texturePool = CreateFromMixins(TexturePoolMixin);
texturePool:OnLoad(parent, layer, textureTemplate, resetterFunc or TexturePool_HideAndClearAnchors);
return texturePool;
end
FontStringPoolMixin = CreateFromMixins(ObjectPoolMixin);
local function FontStringPoolFactory(fontStringPool)
return fontStringPool.parent:CreateFontString(nil, fontStringPool.layer, fontStringPool.fontStringTemplate);
end
function FontStringPoolMixin:OnLoad(parent, layer, fontStringTemplate, resetterFunc)
ObjectPoolMixin.OnLoad(self, FontStringPoolFactory, resetterFunc);
self.parent = parent;
self.layer = layer;
self.fontStringTemplate = fontStringTemplate;
end
FontStringPool_Hide = FramePool_Hide;
FontStringPool_HideAndClearAnchors = FramePool_HideAndClearAnchors;
function CreateFontStringPool(parent, layer, fontStringTemplate, resetterFunc)
local fontStringPool = CreateFromMixins(FontStringPoolMixin);
fontStringPool:OnLoad(parent, layer, fontStringTemplate, resetterFunc or FontStringPool_HideAndClearAnchors);
return fontStringPool;
end
ActorPoolMixin = CreateFromMixins(ObjectPoolMixin);
local function ActorPoolFactory(actorPool)
return actorPool.parent:CreateActor(nil, actorPool.actorTemplate);
end
function ActorPoolMixin:OnLoad(parent, actorTemplate, resetterFunc)
ObjectPoolMixin.OnLoad(self, ActorPoolFactory, resetterFunc);
self.parent = parent;
self.actorTemplate = actorTemplate;
end
ActorPool_Hide = FramePool_Hide;
function ActorPool_HideAndClearModel(actorPool, actor)
actor:ClearModel();
actor:Hide();
end
function CreateActorPool(parent, actorTemplate, resetterFunc)
local actorPool = CreateFromMixins(ActorPoolMixin);
actorPool:OnLoad(parent, actorTemplate, resetterFunc or ActorPool_HideAndClearModel);
return actorPool;
end
FramePoolCollectionMixin = {};
function CreateFramePoolCollection()
local poolCollection = CreateFromMixins(FramePoolCollectionMixin);
poolCollection:OnLoad();
return poolCollection;
end
function FramePoolCollectionMixin:OnLoad()
self.pools = {};
end
function FramePoolCollectionMixin:GetNumActive()
local numTotalActive = 0;
for _, pool in pairs(self.pools) do
numTotalActive = numTotalActive + pool:GetNumActive();
end
return numTotalActive;
end
function FramePoolCollectionMixin:GetOrCreatePool(frameType, parent, template, resetterFunc, forbidden)
local pool = self:GetPool(template);
if not pool then
pool = self:CreatePool(frameType, parent, template, resetterFunc, forbidden);
end
return pool;
end
function FramePoolCollectionMixin:CreatePool(frameType, parent, template, resetterFunc, forbidden)
assert(self:GetPool(template) == nil);
local pool = CreateFramePool(frameType, parent, template, resetterFunc, forbidden);
self.pools[template] = pool;
return pool;
end
function FramePoolCollectionMixin:GetPool(template)
return self.pools[template];
end
function FramePoolCollectionMixin:Acquire(template)
local pool = self:GetPool(template);
assert(pool);
return pool:Acquire();
end
function FramePoolCollectionMixin:Release(object)
for _, pool in pairs(self.pools) do
if pool:Release(object) then
-- Found it! Just return
return;
end
end
-- Huh, we didn't find that object
assert(false);
end
function FramePoolCollectionMixin:ReleaseAllByTemplate(template)
local pool = self:GetPool(template);
if pool then
pool:ReleaseAll();
end
end
function FramePoolCollectionMixin:ReleaseAll()
for key, pool in pairs(self.pools) do
pool:ReleaseAll();
end
end
function FramePoolCollectionMixin:EnumerateActiveByTemplate(template)
local pool = self:GetPool(template);
if pool then
return pool:EnumerateActive();
end
return nop;
end
function FramePoolCollectionMixin:EnumerateActive()
local currentPoolKey, currentPool = next(self.pools, nil);
local currentObject = nil;
return function()
if currentPool then
currentObject = currentPool:GetNextActive(currentObject);
while not currentObject do
currentPoolKey, currentPool = next(self.pools, currentPoolKey);
if currentPool then
currentObject = currentPool:GetNextActive();
else
break;
end
end
end
return currentObject;
end, nil;
end
FixedSizeFramePoolCollectionMixin = CreateFromMixins(FramePoolCollectionMixin);
function CreateFixedSizeFramePoolCollection()
local poolCollection = CreateFromMixins(FixedSizeFramePoolCollectionMixin);
poolCollection:OnLoad();
return poolCollection;
end
function FixedSizeFramePoolCollectionMixin:OnLoad()
FramePoolCollectionMixin.OnLoad(self);
self.sizes = {};
end
function FixedSizeFramePoolCollectionMixin:CreatePool(frameType, parent, template, resetterFunc, forbidden, maxPoolSize, preallocate)
local pool = FramePoolCollectionMixin.CreatePool(self, frameType, parent, template, resetterFunc, forbidden);
if preallocate then
for i = 1, maxPoolSize do
pool:Acquire();
end
pool:ReleaseAll();
end
self.sizes[template] = maxPoolSize;
return pool;
end
function FixedSizeFramePoolCollectionMixin:Acquire(template)
local pool = self:GetPool(template);
assert(pool);
if pool:GetNumActive() < self.sizes[template] then
return pool:Acquire();
end
return nil;
end