SirTony
2/4/2014 - 9:26 PM

This is a port of the XNA generic resource pool (http://www.xnawiki.com/index.php/Generic_Resource_Pool) in the D programming language.

This is a port of the XNA generic resource pool (http://www.xnawiki.com/index.php/Generic_Resource_Pool) in the D programming language.

module resourcepool;

import std.traits;

public final class Pool( TClass ) if( !is( TClass == struct ) && !( isIntegral!TClass || isFloatingPoint!TClass ) && !is( TClass == bool ) && !isSomeChar!TClass )
{
	private alias void delegate( TClass ) Action;
	private alias bool delegate( TClass ) Predicate;
	private alias TClass delegate() Func;
	
	private const int RESIZE_AMOUNT = 10;
	
	private bool mCanResize;
	private TClass[] mItems;
	
	private Predicate mValidate;
	private Func mAllocate;
	
	private Action mInitialize;
	private Action mDeinitialize;
	
	private int mInvalidCount;
	
	public Action Initialize() @property
	{
		return this.mInitialize;
	}
	
	public void Initialize( Action iAction ) @property
	{
		this.mInitialize = iAction;
	}
	
	public Action Deinitialize() @property
	{
		return this.mDeinitialize;
	}
	
	public void Deinitialize( Action iAction ) @property
	{
		this.mDeinitialize = iAction;
	}
	
	public int ValidCount() @property
	{
		return this.mItems.length - this.mInvalidCount;
	}
	
	public int InvalidCount() @property
	{
		return this.mInvalidCount;
	}
	
	private void InvalidCount( int count ) @property
	{
		this.mInvalidCount = count;
	}
	
	public TClass opIndex( int index )
	{
		index += this.mInvalidCount;
		
		if( index < this.mInvalidCount || index >= this.mItems.length )
			throw new Exception( "The index must be less than or equal to ValidCount." );
		
		return this.mItems[index];
	}
	
	public this( int initialSize, bool canResize, Predicate validator, Func allocator )
	in
	{
		assert( initialSize < 1, "initialSize must be at least 1." );
		assert( validator !is null, "validator cannot be null." );
		assert( allocator !is null, "allocator cannot be null." );
	}
	body
	{
		this.mCanResize = canResize;
		this.mItems = new TClass[initialSize];
		this.mInvalidCount = this.mItems.length;
		
		this.mValidate = validator;
		this.mAllocate = allocator;
	}
	
	public void CleanUp()
	{
		for( int i = this.mInvalidCount; i < this.mItems.length; ++i )
		{
			TClass obj = this.mItems[i];
			
			if( this.mValidate( obj ) )
				continue;
			
			if( i != this.mInvalidCount )
			{
				this.mItems[i] = this.mItems[this.mInvalidCount];
				this.mItems[this.mInvalidCount] = obj;
			}
			
			if( this.Deinitialize !is null )
				this.Deinitialize()( obj );
			
			++this.mInvalidCount;
		}
	}
	
	public TClass New()
	{
		if( this.mInvalidCount == 0 )
		{
			if( !this.mCanResize )
				return null;
			
			this.mItems ~= new TClass[RESIZE_AMOUNT];
			this.mInvalidCount += RESIZE_AMOUNT;
		}
		
		--this.mInvalidCount;
		
		TClass obj = this.mItems[this.mInvalidCount];
		
		if( obj is null )
		{
			obj = this.mAllocate();
			
			if( obj is null )
				throw new Exception( "Error allocating new resource." );
			
			this.mItems[this.mInvalidCount] = obj;
		}
		
		if( this.Initialize !is null )
			this.Initialize()( obj );
		
		return obj;
	}
}