/*======================================================================================

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkCudaMemoryPool.h
	Version:		$Revision: 2774 $
	Date:			$Date: 2012-03-13 10:52:35 +0100 (Di, 13 Mrz 2012) $

	Copyright (c) 2010-2011
	Pattern Recognition Lab, 
    University Erlangen-Nuremberg, Germany
    All rights reserved.

	This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
	See RITKCopyright.txt for more information.

	http://www5.informatik.uni-erlangen.de/research/software/ritk

========================================================================================*/

#ifndef CUDAMEMORYPOOL_H__
#define CUDAMEMORYPOOL_H__

#include <list>

#include <itkObject.h>
#include <itkObjectFactory.h>

namespace ritk
{

/**	@ingroup	Cuda
 *	@class		CudaMemoryPool
 *	@brief		Pool for CUDA memory
 *	@author		Jakob Wasza
 *
 *	@details
 *	This class provides a pool for CUDA memory. The size (in elements) for each pool slot
 *	must be provided during pool initialization (constructor) whilst the pool size can be
 *	adjusted during the pools lifetime. The memory pool is nothing else but an array holding
 *	PoolSize memory container, each providing storage for SlotSize elements. The memory container
 *	is defined by the template argument of this class.
 */
template<class TContainerType>
class CudaMemoryPool : public itk::Object
{
public:
	/**	@name	Std typedefs */
	//@{
	typedef CudaMemoryPool						Self;
	typedef itk::Object							Superclass;
	typedef itk::SmartPointer<Self>				Pointer;
	typedef itk::SmartPointer<const Self>		ConstPointer;
	//@}

	/**	@name	Convenience typedefs */
	//@{
	typedef TContainerType						ContainerType;
	typedef typename ContainerType::Pointer		ContainerPointer;
	typedef typename ContainerType::SizeType	SizeType;
	//@}

	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(CudaMemoryPool, itk::Object);

	/**	@brief	Get the current size of the memory pool
	 *	@return	The current size
	 *
	 *	@details
	 *	This method will return the size (number of slots) of the memory pool. 
	 */
	unsigned int GetCurrentPoolSize();

	/**	@name	Set/get the slot size in elements for each dimension */
	//@{
	void SetSlotSize(SizeType size);
	const SizeType &GetSlotSize() const;
	SizeType GetSlotSize();
	//@}

	/**	@brief	Resize the memory pool 
	 *	@param[in]	N	The new number of slots
	 *	@return	true on success, false otherwise
	 *
	 *	@details
	 *	This method will resize the memory pool to match the given argument. If the argument is leq
	 *	than the current pool size false will be returned and no resizing performed.
	 */
	bool ResizePool(unsigned int N);

	/**	@brief	Request a slot
	 *	@return	The ID of the reserved slot
	 *
	 *	@details
	 *	This method will request a slot. The corresponding slot ID is returned. If no slot is available,
	 *	the pool will be automatically resized.
	 */
	unsigned int RequestSlot();

	/**	@brief	Release a slot
	 *	@param[in]	SlotID	The ID of a previously requested slot
	 *
	 *	@details
	 *	This method will release a previously requested slot and mark it as available.
	 */
	void ReleaseSlot(unsigned int SlotID);


	/**	@brief		Get the container associated to a slot
	 *	@param[in]	SlotID	The slot ID
	 *	@return		A pointer to the container associated to the slot
	 *
	 *	@details
	 *	This method will return the container associated to a certain slot. Note that due to performance
	 *	reasons there is no check for validity of the given ID.
	 */
	ContainerPointer GetContainer(unsigned int SlotID);

	/// For convenience. @sa GetMemoryPointer()
	ContainerPointer operator[](unsigned int SlotID);

protected:
	/// Constructor
	CudaMemoryPool();
	/// Destructor
	virtual ~CudaMemoryPool();


protected:
	/// The actual pool
	ContainerPointer *m_Pool;
	/// Slot availability
	bool *m_SlotAvailability;

	/// List holding the free slot ids
	std::list<unsigned int> m_FreeSlotIDs;

	/// The current size of the memory pool
	unsigned int m_PoolSize;
	/// Size of the slots 
	SizeType m_Size;

private:
	/// purposely not implemented
	CudaMemoryPool(const Self&); 
	/// purposely not implemented
	void operator=(const Self&);
	
};

} // ritk

#endif // CUDAMEMORYPOOL_H__
