Quantcast

Add new module that manages pools of reference-counted tables.

Johnny C. Lam [11-10-13 - 00:31]
Add new module that manages pools of reference-counted tables.

This implementation is intrusive -- it adds additional properties to the
tables that it returns from the pools.

git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1148 d5049fe3-3747-40f7-a4b5-f36d6801af5f
Filename
Ovale.toc
OvalePoolRefCount.lua
diff --git a/Ovale.toc b/Ovale.toc
index 3759be6..1d5196d 100644
--- a/Ovale.toc
+++ b/Ovale.toc
@@ -28,6 +28,7 @@ OvaleGUID.lua
 OvaleLatency.lua
 OvalePool.lua
 OvalePoolGC.lua
+OvalePoolRefCount.lua
 OvalePower.lua
 OvaleQueue.lua
 OvaleSpellBook.lua
diff --git a/OvalePoolRefCount.lua b/OvalePoolRefCount.lua
new file mode 100644
index 0000000..7a1f9e2
--- /dev/null
+++ b/OvalePoolRefCount.lua
@@ -0,0 +1,122 @@
+--[[--------------------------------------------------------------------
+    Ovale Spell Priority
+    Copyright (C) 2013 Johnny C. Lam
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License in the LICENSE
+    file accompanying this program.
+--]]--------------------------------------------------------------------
+
+--[[
+	Reference-counting table pool.
+
+	Tables from the pool have four properties added automatically:
+
+	_refcount_pool_object	reference to pool from which the table came.
+	GetReference()			increments the count of references to this table.
+	ReleaseReference()		decrements the count of references to this table and
+							releases the table back to the pool if then count is zero.
+	ReferenceCount()		the count of references to this table.
+--]]
+
+local _, Ovale = ...
+local OvalePoolRefCount = Ovale:NewModule("OvalePoolRefCount")
+Ovale.OvalePoolRefCount = OvalePoolRefCount
+
+--<private-static-properties>
+local assert = assert
+local setmetatable = setmetatable
+local tinsert = table.insert
+local tostring = tostring
+local tremove = table.remove
+local wipe = table.wipe
+--</private-static-properties>
+
+--<public-static-properties>
+OvalePoolRefCount.name = "OvalePoolRefCount"
+OvalePoolRefCount.pool = nil
+OvalePoolRefCount.refcount = nil
+OvalePoolRefCount.size = 0
+OvalePoolRefCount.unused = 0
+OvalePoolRefCount.__index = OvalePoolRefCount
+--</public-static-properties>
+
+--<private-static-methods>
+local function ReferenceCount(item)
+	return item._refcount_pool_object.refcount[item] or 0
+end
+
+local function GetReference(item)
+	local refcount = item:ReferenceCount()
+	item._refcount_pool_object.refcount[item] = refcount + 1
+	return item
+end
+
+local function ReleaseReference(item)
+	local refcount = item:ReferenceCount()
+	local poolObject = item._refcount_pool_object
+	if refcount > 1 then
+		poolObject.refcount[item] = refcount - 1
+	else
+		poolObject.refcount[item] = nil
+		wipe(item)
+		tinsert(poolObject.pool, item)
+		poolObject.unused = poolObject.unused + 1
+	end
+	return item
+end
+--</private-static-methods>
+
+--<private-static-properties>
+local itemPrototype = {
+	_refcount_pool_object = nil,
+	AddReference = AddReference,
+	ReferenceCount = ReferenceCount,
+	ReleaseReference = ReleaseReference,
+}
+--</private-static-properties>
+
+--<public-static-methods>
+do
+	-- Class constructor
+	setmetatable(OvalePoolRefCount, { __call = function(self, ...) return self:NewPool(...) end })
+end
+
+function OvalePoolRefCount:NewPool(name)
+	name = name or self.name
+	local obj = setmetatable({ name = name }, self)
+	obj.refcount = {}
+	obj:Drain()
+	return obj
+end
+
+function OvalePoolRefCount:Get()
+	assert(self.pool and self.refcount)
+	local item = tremove(self.pool)
+	if item then
+		self.unused = self.unused - 1
+	else
+		self.size = self.size + 1
+		item = {}
+	end
+	for name, method in pairs(itemPrototype) do
+		item[name] = method
+	end
+	item._refcount_pool_object = self
+	return item:GetReference()
+end
+
+function OvalePoolRefCount:Release(item)
+	item:ReleaseReference()
+end
+
+function OvalePoolRefCount:Drain()
+	self.pool = {}
+	self.size = self.size - self.unused
+	self.unused = 0
+end
+
+function OvalePoolRefCount:Debug()
+	Ovale:FormatPrint("Pool %s has size %d with %d item(s).", tostring(self.name), self.size, self.unused)
+end
+--</public-static-methods>