Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TCG_POOL_H
Toshihiro Shimizu 890ddd
#define TCG_POOL_H
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include "assert.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <vector></vector>
Toshihiro Shimizu 890ddd
#include <algorithm></algorithm>
Toshihiro Shimizu 890ddd
#include <functional></functional>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Discriminate rvalues support - either use Boost's config.hpp for automatic lookup,
Toshihiro Shimizu 890ddd
// or deal with it manually
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TCG_RVALUES_SUPPORT
Toshihiro Shimizu 890ddd
#include <boost config.hpp=""></boost>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef BOOST_NO_RVALUE_REFERENCES
Toshihiro Shimizu 890ddd
#define TCG_RVALUES_SUPPORT 0
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#define TCG_RVALUES_SUPPORT 1
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  \file     pool.h
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \brief    This file contains an implementation of the \a pool container concept.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \details  A pool is a container that supports two fundamental operations, acquire() and
Toshihiro Shimizu 890ddd
            release(), whose purpose is that of marking access operations to a resource
Toshihiro Shimizu 890ddd
            that should not be destroyed when the access operation ends.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            Creation and destruction of resources can be a time-consuming task that could
Toshihiro Shimizu 890ddd
            be avoided when it is known that resources could be reused - which is the very
Toshihiro Shimizu 890ddd
            reason why caching can be a useful approach to some problems.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            The classical cache concept is nothing more than that of a standard associative
Toshihiro Shimizu 890ddd
            map, tweaked to accomodate specific commodities - such as managing the cache
Toshihiro Shimizu 890ddd
            size.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            However, sometimes resources could be considered to be effectively indentical,
Toshihiro Shimizu 890ddd
            to the point that assigning a key is merely a way to keep the objects
Toshihiro Shimizu 890ddd
            distinct in the cache. Users are in the condition to require only two functions,
Toshihiro Shimizu 890ddd
            one to acquire() a resource, the other to release() it.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            The Pool concept we are introducing satisfies the following ruleset:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
            
    Toshihiro Shimizu 890ddd
                
  • The pool is a dynamical container which allocates resources by invoking the
  • Toshihiro Shimizu 890ddd
                     objects' default constructor. 
    Toshihiro Shimizu 890ddd
                
  • Objects in the pool are \b not destructed, except when the pool is explicitly
  • Toshihiro Shimizu 890ddd
                     \a squeezed by the user.
    Toshihiro Shimizu 890ddd
                
  • Keys are indices, returned by the pool with an incremental ordering.
  • Toshihiro Shimizu 890ddd
                
  • An object which has been acquired cannot be acquired again until it has been
  • Toshihiro Shimizu 890ddd
                     released 
    Toshihiro Shimizu 890ddd
                
    Toshihiro Shimizu 890ddd
    */
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    namespace tcg
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //****************************************************************************
    Toshihiro Shimizu 890ddd
    //    TCG Indices Pool  class
    Toshihiro Shimizu 890ddd
    //****************************************************************************
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    template <typename cont="std::vector&lt;T" t="size_t," typename="">></typename>
    Toshihiro Shimizu 890ddd
    class indices_pool
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    public:
    Toshihiro Shimizu 890ddd
    	typedef T value_type;
    Toshihiro Shimizu 890ddd
    	typedef Cont container_type;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    private:
    Toshihiro Shimizu 890ddd
    	T m_start;				//!< First index to be acquired
    Toshihiro Shimizu 890ddd
    	T m_size;				//!< Current indices count
    Toshihiro Shimizu 890ddd
    	Cont m_releasedIndices; //!< Priority queue of released indices
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    public:
    Toshihiro Shimizu 890ddd
    	indices_pool(value_type start = 0) : m_start(start), m_size(0) {}
    Toshihiro Shimizu 890ddd
    	~indices_pool() {}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	template <typename iter=""></typename>
    Toshihiro Shimizu 890ddd
    	indices_pool(value_type size, iter releasedBegin, iter releasedEnd, value_type start = 0)
    Toshihiro Shimizu 890ddd
    		: m_start(start), m_size(size), m_releasedIndices(releasedBegin, releasedEnd)
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		std::make_heap(m_releasedIndices.begin(), m_releasedIndices.end(), std::greater<t>());</t>
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	template <typename iter=""></typename>
    Toshihiro Shimizu 890ddd
    	indices_pool(iter acquiredBegin, iter acquiredEnd, value_type start = 0)
    Toshihiro Shimizu 890ddd
    		: m_start(start)
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		if (acquiredBegin == acquiredEnd)
    Toshihiro Shimizu 890ddd
    			m_size = 0;
    Toshihiro Shimizu 890ddd
    		else {
    Toshihiro Shimizu 890ddd
    			// Sort the acquired indices
    Toshihiro Shimizu 890ddd
    			std::vector<t> acquired(acquiredBegin, acquiredEnd);</t>
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			std::sort(acquired.begin(), acquired.end());
    Toshihiro Shimizu 890ddd
    			assert(acquired.front() >= m_start);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			// Scan them, adding holes in the acquired sequence to released indices
    Toshihiro Shimizu 890ddd
    			m_size = acquired.back() - m_start + 1;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			assert(m_size >= (T)acquired.size());
    Toshihiro Shimizu 890ddd
    			m_releasedIndices.reserve(m_size - acquired.size());
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			T curIdx = m_start;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			typename std::vector<t>::iterator at, aEnd(acquired.end());</t>
    Toshihiro Shimizu 890ddd
    			for (at = acquired.begin(); at != aEnd; ++at, ++curIdx)
    Toshihiro Shimizu 890ddd
    				for (; curIdx != *at; ++curIdx)
    Toshihiro Shimizu 890ddd
    					m_releasedIndices.push_back(curIdx);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			std::make_heap(m_releasedIndices.begin(), m_releasedIndices.end(), std::greater<t>());</t>
    Toshihiro Shimizu 890ddd
    		}
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	value_type size() const { return m_size; }
    Toshihiro Shimizu 890ddd
    	value_type releasedSize() const { return m_releasedIndices.size(); }
    Toshihiro Shimizu 890ddd
    	value_type acquiredSize() const { return size() - releasedSize(); }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	const container_type &releasedIndices() const { return m_releasedIndices; }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	value_type acquire()
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		if (!m_releasedIndices.empty()) {
    Toshihiro Shimizu 890ddd
    			value_type idx = m_releasedIndices.front();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			pop_heap(m_releasedIndices.begin(), m_releasedIndices.end(), std::greater<t>());</t>
    Toshihiro Shimizu 890ddd
    			m_releasedIndices.pop_back();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			return idx;
    Toshihiro Shimizu 890ddd
    		}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		return m_start + m_size++;
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	void release(value_type idx)
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		m_releasedIndices.push_back(idx);
    Toshihiro Shimizu 890ddd
    		push_heap(m_releasedIndices.begin(), m_releasedIndices.end(), std::greater<t>());</t>
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	void clear()
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		m_size = 0;
    Toshihiro Shimizu 890ddd
    		m_releasedIndices.clear();
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//! Removes pool entries whose index is beyond that of the last acquired one.
    Toshihiro Shimizu 890ddd
    	void squeeze()
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		if (m_releasedIndices.empty())
    Toshihiro Shimizu 890ddd
    			return;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		std::sort_heap(m_releasedIndices.begin(), m_releasedIndices.end(), std::greater<t>()); // O(n logn)</t>
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		// Decrease the pool size as long as the back items are unused
    Toshihiro Shimizu 890ddd
    		T lastIndex = m_start + m_size - 1;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		typename Cont::iterator ut, uEnd(m_releasedIndices.end());
    Toshihiro Shimizu 890ddd
    		for (ut = m_releasedIndices.begin(); ut != uEnd && *ut == lastIndex; ++ut)
    Toshihiro Shimizu 890ddd
    			--lastIndex, --m_size;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		if (ut != m_releasedIndices.begin())
    Toshihiro Shimizu 890ddd
    			m_releasedIndices.swap(Cont(ut, uEnd));
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		std::make_heap(m_releasedIndices.begin(), m_releasedIndices.end(), std::greater<t>()); // O(n)</t>
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    #if (TCG_RVALUES_SUPPORT > 0)
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	indices_pool(const indices_pool &other)
    Toshihiro Shimizu 890ddd
    		: m_start(other.m_start), m_size(other.m_size), m_releasedIndices(other.m_releasedIndices)
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	indices_pool &operator=(const indices_pool &other)
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		m_start = other.m_start, m_size = other.m_size, m_releasedIndices = other.m_releasedIndices;
    Toshihiro Shimizu 890ddd
    		return *this;
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	indices_pool(indices_pool &&other)
    Toshihiro Shimizu 890ddd
    		: m_start(other.m_start), m_size(other.m_size), m_releasedIndices(std::forward<container_type &&="">(other.m_releasedIndices)) {}</container_type>
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	indices_pool &operator=(indices_pool &&other)
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		m_start = other.m_start, m_size = other.m_size;
    Toshihiro Shimizu 890ddd
    		m_releasedIndices = std::forward<container_type &&="">(other.m_releasedIndices);</container_type>
    Toshihiro Shimizu 890ddd
    		return *this;
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    #endif
    Toshihiro Shimizu 890ddd
    };
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //----------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    template <typename cont="std::vector&lt;T" t,="" typename="">></typename>
    Toshihiro Shimizu 890ddd
    class pool
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    public:
    Toshihiro Shimizu 890ddd
    	typedef T value_type;
    Toshihiro Shimizu 890ddd
    	typedef Cont container_type;
    Toshihiro Shimizu 890ddd
    	typedef size_t size_type;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    private:
    Toshihiro Shimizu 890ddd
    	Cont m_objects;						 //!< Objects in the pool
    Toshihiro Shimizu 890ddd
    	tcg::indices_pool<size_t> m_indices; //!< Indices Pool representing m_objects</size_t>
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    public:
    Toshihiro Shimizu 890ddd
    	pool() {}
    Toshihiro Shimizu 890ddd
    	~pool() {}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	const tcg::indices_pool<size_t> &indices() const { return m_indices; }</size_t>
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	size_type size() const
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		assert(m_indices.size() <= m_objects.size());
    Toshihiro Shimizu 890ddd
    		return m_objects.size();
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    	size_type releasedSize() const { return m_objects.size() - m_indices.acquiredSize(); }
    Toshihiro Shimizu 890ddd
    	size_type acquiredSize() const { return m_indices.acquiredSize(); }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	const value_type &operator[](size_type idx) const { return m_objects[idx]; }
    Toshihiro Shimizu 890ddd
    	value_type &operator[](size_type idx) { return m_objects[idx]; }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	size_type acquire()
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		size_t result = m_indices.acquire();
    Toshihiro Shimizu 890ddd
    		if (result >= m_objects.size()) {
    Toshihiro Shimizu 890ddd
    			assert(result == m_objects.size());
    Toshihiro Shimizu 890ddd
    			m_objects.push_back(T());
    Toshihiro Shimizu 890ddd
    		}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		return result;
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	void release(size_type idx) { m_indices.release(idx); }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	void releaseAll() { m_indices.clear(); }
    Toshihiro Shimizu 890ddd
    	void clear()
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		releaseAll();
    Toshihiro Shimizu 890ddd
    		m_objects.clear();
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	//! Removes pool entries whose index is beyond that of the last acquired one.
    Toshihiro Shimizu 890ddd
    	void squeeze()
    Toshihiro Shimizu 890ddd
    	{
    Toshihiro Shimizu 890ddd
    		m_indices.squeeze();
    Toshihiro Shimizu 890ddd
    		m_objects.resize(m_indices.size());
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    };
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    } // namespace tcg
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    #endif // TCG_POOL_H