#include "stdafx.h"
#include "Pool.h"
  // Create a new pool by defining the number of items to preallocate, and the
// size of each item.  For situations where you do not want the allocation
// pool increase in size, set bGrow to false.
CPool::CPool(const WORD nPoolSize, const size_t nItemSize, const bool bGrow) :
	m_pPrev(0),
	m_pNext(0),
	m_nPoolSize(nPoolSize),
	m_nItemSize(nItemSize),
	m_nTOS(0),
	m_bGrow(bGrow)
{
	m_pPool = reinterpret_cast<BYTE*>(::operator new(m_nItemSize * m_nPoolSize));
	m_pFreeStack = new BYTE*[m_nPoolSize];
	m_pAvailable = m_pPool;
	m_pLast = m_pPool + m_nItemSize * m_nPoolSize;
}
  // Add a new pool to the end of the linked list, this can only be called from
// another CPool.
CPool::CPool(CPool* const pPrev) :
	m_pPrev(pPrev),
	m_pNext(0),
	m_nPoolSize(pPrev->m_nPoolSize),
	m_nItemSize(pPrev->m_nItemSize),
	m_nTOS(0),
	m_bGrow(true)
{
	m_pPool = reinterpret_cast<BYTE*>(::operator new(m_nItemSize * m_nPoolSize));
	m_pFreeStack = new BYTE*[m_nPoolSize];
	m_pAvailable = m_pPool;
	m_pLast = m_pPool + m_nItemSize * m_nPoolSize;
}
  CPool::~CPool()
{
	delete m_pNext;
	delete m_pPool;
	delete [] m_pFreeStack;
}
  void* CPool::New(const size_t size)
{
	// If the item being requested is not the right size then use the generalised
	// new operator.  This will occur if the object is derived from the allocated
	// class.
	if (size != m_nItemSize)
		return ::operator new(size);
  	// If there are any holes in the free stack then fill them up.
	if (m_nTOS == 0)
	{
		// If there is any space left in this pool then use it, otherwise move
		// on to the next in the linked list.
		if (m_pAvailable < m_pLast)
		{
			BYTE*	pReturn = m_pAvailable;
			m_pAvailable += m_nItemSize;
			return reinterpret_cast<void*>(pReturn);
		}
		else
		{
			// If there is another pool in the list then pass the request on to
			// it, otherwise try to create a new pool.
			if (m_pNext)
			{
				return m_pNext->New(size);
			}
			else
			{
				if (m_bGrow)
				{
					m_pNext = new CPool(this);
					if (m_pNext)
						return m_pNext->New(size);
				}
				// If we cannot allocate a new pool then return 0.
				return 0;
			}
		}
	}
	else
		return reinterpret_cast<void*>(m_pFreeStack[--m_nTOS]);
}
  void CPool::Delete(void* pVoid)
{
	if (pVoid)
	{
		BYTE*	pItem = reinterpret_cast<BYTE*>(pVoid);
  		// Check if the item being deleted is within this pool's memory range.
		if (pItem < m_pPool || pItem >= m_pLast)
		{
			// If there is another pool in the list then try to delete from it,
			// otherwise call the generalised delete operator.
			if (m_pNext)
				m_pNext->Delete(pItem);
			else
				::operator delete(pVoid);
		}
		else
		{
			// Add a hole to the free stack.
			m_pFreeStack[m_nTOS++] = pItem;
  			// If this pool is empty and it is the last in the linked list
			// then delete it and set the previous pool to the last.
			if (m_pPrev && !m_pNext &&
				static_cast<long>(m_nTOS * m_nItemSize) == m_pAvailable - m_pPool)
			{
				m_pPrev->m_pNext = 0;
				delete this;
			}
		}
	}
}
  // Reset all the pointers and indices, effectively deleting the allocated
// items without actually calling their destructors.  This function should
// be used with extreme caution since all sorts of horrible things can result
// from it's misuse.
void CPool::Purge()
{
	m_nTOS = 0;
	m_pAvailable = m_pPool;
	if (m_pNext)
		m_pNext->Purge();
}
   |