Object Pools Manager

Hello! I have been working on my voxel terrain system and while I was thinking off how I can optimize the performance, I came up with idea of creating object pools manager.

local module = {
}

function module:New() : PoolManager
	
	local PoolsManager = {
		Pools = {

		};
		CanAddObjects = {
		 	
		};
		CreateMethods = {
			
		};
		TYPES_NULL = {
			
		};
		NewMethods = {
			
		};
		Lengths = {
			
		};
		Keys = {

		}
	}
	
	function PoolsManager:CreatePool(Key,TYPE_NULL:any,CanAddObjects : boolean,NewMethod)
		local Index = #self.Pools + 1
		self.Lengths[Index] = 0
		self.Pools[Index] = {}
		self.CanAddObjects[Index] = CanAddObjects == true
		self.NewMethods[Index] = NewMethod or function() return TYPE_NULL end
		self.Keys[Key] = Index
		self.TYPES_NULL[Index] = TYPE_NULL
		return Index
	end
	
	function PoolsManager:GetIndexFromKey(Key)
		return self.Keys[Key]
	end
	
	function PoolsManager:InsertObject(Index,Object)
		table.insert(self.Pools[Index],Object)
		self.Lengths[Index] += 1
	end
	
	function PoolsManager:PopObject(Index)
		local Pool = self.Pools[Index]
		local Length = self.Lengths[Index]
		
		if (Length > 0) then
			local Top = Pool[Length]
			Pool[Length] = self.TYPES_NULL[Index]
			self.Lengths[Index] -= 1
			return Top
		elseif (self.CanAddObjects[Index]) then
			return self.NewMethods[Index]()
		else
			return self.TYPES_NULL[Index]
		end
		
	end
    return PoolsManager	
end

export type PoolManager = typeof(module:New())
return module

It’s a simple module, which contains a set of methods.
But let’s come to the explaining part of how these work.

  1. CreatePool(Key, TYPE_NULL, CanAddObjects, NewMethod): This method creates a pool for objects of a specific type. It takes four arguments:
  • Key: The key used to identify the pool. It serves as a unique identifier for the pool.
  • TYPE_NULL: The default value to be returned by the PopObject method if the pool is empty and cannot create a new object. It represents a null value for the type.
  • CanAddObjects: A boolean value indicating whether new objects can be added to the pool when it runs out of objects. If CanAddObjects is set to true, the NewMethod will be used to create a new object for the pool.
  • NewMethod: A function that creates a new object for the pool. If CanAddObjects is true and the pool is empty, this method will be called to generate a new object for the pool.
  1. GetIndexFromKey(Key): This method retrieves the index of a pool based on its key. It takes one argument:
  • Key: The key used to identify the pool.It returns the index of the pool associated with the provided key.
  1. InsertObject(Index, Object): This method inserts an object into the specified pool. It takes two arguments:
  • Index: The index of the pool where the object will be inserted.
  • Object: The object to be inserted into the pool.The method adds the object to the pool’s table and increments the length of the pool.
  1. PopObject(Index): This method retrieves an object from the specified pool. It takes one argument:
  • Index: The index of the pool from which the object will be retrieved.The method checks if the pool has any objects. If it does, the last object from the pool’s table is retrieved, the length of the pool is decremented, and the object is returned. If the pool is empty and CanAddObjects is true, the NewMethod is called to create a new object for the pool. If the pool is empty and CanAddObjects is false, the TYPE_NULL value associated with the pool is returned.

Here is an example how to use this:

local PoolManagerModule = require(script.PoolManagerModule) 

local poolManager = PoolManagerModule:New()

local Object = {}

function Object.new(value)
    local obj = {
        value = value
    }
    setmetatable(obj, { __index = Object })
    return obj
end

function Object:PrintValue()
    print("Value:", self.value)
end

local TYPE_NULL = Object.new(-math.huge)

local objectPoolIndex = poolManager:CreatePool("ObjectPool",TYPE_NULL, false)

-- Insert objects into the pool
for i = 1, 10 do
    local obj = Object.new(i)
    poolManager:InsertObject(objectPoolIndex, obj)
end

-- Retrieve objects from the pool
for i = 1, 12 do
    local obj = poolManager:PopObject(objectPoolIndex)
    if obj ~= TYPE_NULL then
        obj:PrintValue()
    else
        print("No available objects in the pool.")
    end
end
1 Like