//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#ifndef H_SPK_POOL
#define H_SPK_POOL
#include "Core/SPK_DEF.h"
namespace SPK
{
/**
* @class Pool
* @brief A generic container to handle a pool of objects
*
* A Pool is a container built upon a std vector.
* It allows to store continuous objects by handling active and inactive ones.
*
* A Pool is designed to be faster than a vector to handle. However, the order of elements is not fixed.
* A Pool holds 2 continuous list of elements : the actives and the inactives :
*
* - When created, elements can either be activate or inactive.
* - When activating an element, the first inactive element is swapped with the element to activate and the number of active elements is increased by 1.
* - When inactivating an element, the last active element is swapped with the element to inactivate and the number of active elements is decreased by 1.
*
* So when activating or disactivating an element, a single swap is used which is faster than the displacement of all following elements when inserting or removing an element from a vector.
* Elements are not removed in a Pool but only inactivated. Typically, elements will be removed when the Pool has to be destroyed or reinitialize.
*
* Another difference with a vector is that the reallocation is not automatic but only manual with a call to reallocate(unsigned int).
* Therefore adding elements to a full Pool will have no effect until its capacity is increased.
*/
template
class Pool
{
public :
/** @brief the iterator of a Pool */
typedef typename std::vector::iterator iterator;
/** @brief the constant iterator of a Pool */
typedef typename std::vector::const_iterator const_iterator;
/** @brief the reverse iterator of a Pool */
typedef typename std::vector::reverse_iterator reverse_iterator;
/** @brief the constant reverse iterator of a Pool */
typedef typename std::vector::const_reverse_iterator const_reverse_iterator;
/** @brief the default capacity of a Pool */
static const unsigned int DEFAULT_CAPACITY = 1000;
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of Pool
*
* The capacity is the maximum number of elements a Pool can hold.
* Unlike a std vector, the capacity is not automatically increased when reaching it.
* The user has to manually make a call to reallocate(unsigned int) to increase the capacity.
* If an elements is added to a full Pool, nothing will happen.
*
* @param capacity : the maximum number of elements the Pool can hold
*/
Pool(size_t capacity = DEFAULT_CAPACITY);
Pool(const Pool& pool);
///////////////
// Operators //
///////////////
Pool& operator=(const Pool& pool);
/**
* @brief Gets the element of the Pool at index
*
* Note that the index is not tested and can therefore be out of bounds.
*
* @param index : the index of the element to access
* @return the accessed element
*/
T& operator[](size_t index);
/**
* @brief Gets the element of the Pool at index
*
* This is the constant version of operator[](size_t).
*
* @param index : the index of the element to access
* @return the accessed element
*/
const T& operator[](size_t index) const;
/////////////
// Getters //
/////////////
/**
* @brief Gets the number of active elements in this Pool
*
* This method is the standard equivalent to getNbActive()
*
* @return the number of active elements in this Pool
* @since 1.01.01
*/
inline size_t size() const;
/**
* @brief Gets the number of active elements in this Pool
*
* This method is equivalent to the standard size()
*
* @return the number of active elements in this Pool
*/
inline size_t getNbActive() const;
/**
* @brief Gets the number of inactive elements in this Pool
* @return the number of inactive elements in this Pool
*/
inline size_t getNbInactive() const;
/**
* @brief Gets the number of elements in this Pool
*
* the number of elements is defined by : number of active elements + number of inactive elements.
*
* @return the number of elements in this Pool
*/
inline size_t getNbTotal() const;
/**
* @brief Gets the capacity of this Pool
*
* The capacity is the maximum number of elements a Pool can hold.
*
* @return the capacity of this Pool
*/
inline size_t getNbReserved() const;
/**
* @brief Gets the room left for new elements in this Pool
*
* This is defined by : capacity - number of elements.
*
* @return the room left in this Pool
*/
inline size_t getNbEmpty() const;
/**
* @brief Gets the maximum number of elements this Pool had
*
* This is useful to check if the capacity is well set or not.
*
* @return the maximum number of elements this Pool had
*/
inline size_t getMaxTotal() const;
///////////////
// Iterators //
///////////////
/**
* @brief Gets an iterator referring to the first active element in this Pool
*
* This method is the standard equivalent to beginActive().
*
* @return an iterator referring to the first active element in this Pool
*/
inline iterator begin();
/**
* @brief Gets an iterator referring to the past-the-end active element in this Pool
*
* This method is the standard equivalent to endActive().
* It also returns the same iterator as beginInactive() but, to respect the syntax, should not be used for the same purpose.
*
* @return an iterator referring to the past-the-end active element in this Pool
*/
inline iterator end();
/**
* @brief Gets an iterator referring to the first active element in this Pool
*
* This method is equivalent to the standard begin().
*
* @return an iterator referring to the first active element in this Pool
*/
inline iterator beginActive();
/**
* @brief Gets an iterator referring to the past-the-end active element in this Pool
*
* This method is equivalent to the standard end().
* It also returns the same iterator as beginInactive() but, to respect the syntax, should not be used for the same purpose.
*
* @return an iterator referring to the past-the-end active element in this Pool
*/
inline iterator endActive();
/**
* @brief Gets an iterator referring to the first inactive element in this Pool
*
* Note that this method retuns the same iterator as end() and endActive(), but due to syntax, should not be use for the same purpose.
*
* @return an iterator referring to the first inactive element in this Pool
*/
inline iterator beginInactive();
/**
* @brief Gets an iterator referring to the past-the-end inactive element in this Pool
* @return an iterator referring to the past-the-end inactive element in this Pool
*/
inline iterator endInactive();
/**
* @brief Gets an iterator referring to the first active element in this Pool
*
* This is the constant version of begin().
*
* @return an iterator referring to the first active element in this Pool
*/
inline const_iterator begin() const;
/**
* @brief Gets an iterator referring to the past-the-end active element in this Pool
*
* This is the constant version of end().
*
* @return an iterator referring to the past-the-end active element in this Pool
*/
inline const_iterator end() const;
/**
* @brief Gets an iterator referring to the first active element in this Pool
*
* This is the constant version of beginActive().
*
* @return an iterator referring to the first active element in this Pool
*/
inline const_iterator beginActive() const;
/**
* @brief Gets an iterator referring to the past-the-end active element in this Pool
*
* This is the constant version of endActive().
*
* @return an iterator referring to the past-the-end active element in this Pool
*/
inline const_iterator endActive() const;
/**
* @brief Gets an iterator referring to the first inactive element in this Pool
*
* This is the constant version of beginInactive().
*
* @return an iterator referring to the first inactive element in this Pool
*/
inline const_iterator beginInactive() const;
/**
* @brief Gets an iterator referring to the past-the-end inactive element in this Pool
*
* This is the constant version of endInactive().
*
* @return an iterator referring to the past-the-end inactive element in this Pool
*/
inline const_iterator endInactive() const;
/**
* @brief Gets a reverse iterator referring to the first active element in this Pool
*
* This method is the standard equivalent to rbeginActive().
*
* @return a reverse iterator referring to the first active element in this Pool
*/
inline reverse_iterator rbegin();
/**
* @brief Gets a reverse iterator referring to the past-the-end active element in this Pool
*
* This method is the standard equivalent to rendActive().
* It also returns the same reverse iterator as rbeginInactive() but, to respect the syntax, should not be used for the same purpose.
*
* @return a reverse iterator referring to the past-the-end active element in this Pool
*/
inline reverse_iterator rend();
/**
* @brief Gets a reverse iterator referring to the first active element in this Pool
*
* This method is equivalent to the standard rbegin().
*
* @return a reverse iterator referring to the first active element in this Pool
*/
inline reverse_iterator rbeginActive();
/**
* @brief Gets a reverse iterator referring to the past-the-end active element in this Pool
*
* This method is equivalent to the standard rend().
* It also returns the same reverse iterator as rbeginInactive() but, to respect the syntax, should not be used for the same purpose.
*
* @return a reverse iterator referring to the past-the-end active element in this Pool
*/
inline reverse_iterator rendActive();
/**
* @brief Gets a reverse iterator referring to the first inactive element in this Pool
*
* Note that this method retuns the same iterator as rend() and rendActive(), but due to syntax, should not be use for the same purpose.
*
* @return a reverse iterator referring to the first inactive element in this Pool
*/
inline reverse_iterator rbeginInactive();
/**
* @brief Gets a reverse iterator referring to the past-the-end inactive element in this Pool
* @return a reverse iterator referring to the past-the-end inactive element in this Pool
*/
inline reverse_iterator rendInactive();
/**
* @brief Gets a reverse iterator referring to the first active element in this Pool
*
* This is the constant version of rbegin().
*
* @return a reverse iterator referring to the first active element in this Pool
*/
inline const_reverse_iterator rbegin() const;
/**
* @brief Gets a reverse iterator referring to the past-the-end active element in this Pool
*
* This is the constant version of rend().
*
* @return a reverse iterator referring to the past-the-end active element in this Pool
*/
inline const_reverse_iterator rend() const;
/**
* @brief Gets a reverse iterator referring to the first active element in this Pool
*
* This is the constant version of rbeginActive().
*
* @return a reverse iterator referring to the first active element in this Pool
*/
inline const_reverse_iterator rbeginActive() const;
/**
* @brief Gets a reverse iterator referring to the past-the-end active element in this Pool
*
* This is the constant version of rendActive().
*
* @return a reverse iterator referring to the past-the-end active element in this Pool
*/
inline const_reverse_iterator rendActive() const;
/**
* @brief Gets a reverse iterator referring to the first inactive element in this Pool
*
* This is the constant version of rbeginInactive().
*
* @return a reverse iterator referring to the first inactive element in this Pool
*/
inline const_reverse_iterator rbeginInactive() const;
/**
* @brief Gets a reverse iterator referring to the past-the-end inactive element in this Pool
*
* This is the constant version of rendInactive().
*
* @return a reverse iterator referring to the past-the-end inactive element in this Pool
*/
inline const_reverse_iterator rendInactive() const;
/////////////////////
// Elements access //
/////////////////////
/**
* @brief Gets the first active element
*
* This method is the standard equivalent to frontActive().
*
* @return the first active element
* @since 1.01.01
*/
inline T& front();
/**
* @brief Gets the last active element
*
* This method is the standard equivalent to backActive().
*
* @return the last active element
* @since 1.01.01
*/
inline T& back();
/**
* @brief Gets the first active element
*
* This method is equivalent to the standard front().
*
* @return the first active element
* @since 1.01.01
*/
inline T& frontActive();
/**
* @brief Gets the last active element
*
* This method is the equivalent to the standard back().
*
* @return the last active element
* @since 1.01.01
*/
inline T& backActive();
/**
* @brief Gets the first inactive element
* @return the first inactive element
* @since 1.01.01
*/
inline T& frontInactive();
/**
* @brief Gets the last inactive element
* @return the last inactive element
* @since 1.01.01
*/
inline T& backInactive();
/**
* @brief Gets the first active element
*
* This is the constant version of front().
*
* @return the first active element
* @since 1.01.01
*/
inline const T& front() const;
/**
* @brief Gets the last active element
*
* This is the constant version of back().
*
* @return the last active element
* @since 1.01.01
*/
inline const T& back() const;
/**
* @brief Gets the first active element
*
* This is the constant version of frontActive().
*
* @return the first active element
* @since 1.01.01
*/
inline const T& frontActive() const;
/**
* @brief Gets the last active element
*
* This is the constant version of backActive().
*
* @return the last active element
* @since 1.01.01
*/
inline const T& backActive() const;
/**
* @brief Gets the first inactive element
*
* This is the constant version of frontInactive().
*
* @return the first inactive element
* @since 1.01.01
*/
inline const T& frontInactive() const;
/**
* @brief Gets the last inactive element
*
* This is the constant version of backInactive().
*
* @return the last inactive element
* @since 1.01.01
*/
inline const T& backInactive() const;
///////////////
// Interface //
///////////////
/**
* @brief Fills the Pool with a copy of the passed element
*
* The Pool is filled entirely which means its number of elements will be equal to its capacity.
* Note that all added elements are inactive.
*
* @param value : the element which will be copied into the Pool
*/
inline void assign(T& value);
/**
* @brief Adds an active element to this Pool
* @param element : the element to add to this Pool
* @return true if the element can be added, false otherwise (if the Pool has no more room left)
*/
bool pushActive(T& element);
/**
* @brief Adds an inactive element to this Pool
* @param element : the element to add to this Pool
* @return true if the element can be added, false otherwise (if the Pool has no more room left)
*/
bool pushInactive(T& element);
/**
* @brief Inactivates an active element
*
* The index is tested and if it does not point to an active element, nothing will happen.
*
* @param index : the index of the active element to inactivate
*/
void makeInactive(size_t index);
/** @brief Inactivates all the elements */
inline void makeAllInactive();
/**
* @brief Activates the first inactive element
*
* A pointer to the activated element is returned.
* If there is no inactive element to activate, NULL is returned.
*
* @return a pointer to the activated element or NULL if there is no element to activate
*/
T* makeActive();
/**
* @brief Activates the index inactive element
*
* The index starts at the first inactive element.
* This method is a bit slower than makeActive() but makeActive() has the same effect as makeActive(0).
*
* If the element at index is out of bounds, NULL is returned
*
* @param index : the inactive element to activate
* @return a pointer to the activated element or NULL if the index is out of bounds
*/
T* makeActive(size_t index);
/**
* @brief Removes an element from this Pool
*
* The index is checked for bounds. If it is out of bounds nothing happens.
*
* Note that either an active or inactive element can be removed.
*
* @param index : the index of the element to remove
*/
void erase(size_t index);
/** @brief Removes all elements in this Pool */
void clear();
/**
* @brief reallocates the Pool
*
* This will invalidates all iterators on the Pool.
* If the new capacity is smaller than the number of elements, nothing happens.
*
* @param capacity : the new desired capacity for this Pool
*/
inline void reallocate(size_t capacity);
private :
std::vector container;
size_t nbActive;
size_t maxTotal;
inline void swapElements(T& a,T& b);
};
template
Pool::Pool(size_t capacity) :
nbActive(0),
maxTotal(0)
{
container.reserve(capacity);
}
template
Pool::Pool(const Pool& pool) :
nbActive(pool.nbActive),
maxTotal(0),
container()
{
// the copy constructor of vector does not copy the capacity !
container.reserve(pool.container.capacity());
container = pool.container;
}
template
Pool& Pool::operator=(const Pool& pool)
{
if (this != &pool)
{
nbActive = pool.nbActive();
maxTotal = 0;
container.reserve(pool.container.capacity());
container = pool.container;
}
return *this;
}
template
T& Pool::operator[](size_t index)
{
return container[index];
}
template
const T& Pool::operator[](size_t index) const
{
return container[index];
}
template
inline size_t Pool::size() const
{
return nbActive;
}
template
inline size_t Pool::getNbActive() const
{
return nbActive;
}
template
inline size_t Pool::getNbInactive() const
{
return container.size() - nbActive;
}
template
inline size_t Pool::getNbTotal() const
{
return container.size();
}
template
inline size_t Pool::getNbReserved() const
{
return container.capacity();
}
template
inline size_t Pool::getNbEmpty() const
{
return container.capacity() - container.size();
}
template
inline size_t Pool::getMaxTotal() const
{
return maxTotal;
}
template
inline typename Pool::iterator Pool::begin()
{
return container.begin();
}
template
inline typename Pool::iterator Pool::end()
{
return container.begin() + nbActive;
}
template
inline typename Pool::iterator Pool::beginActive()
{
return begin();
}
template
inline typename Pool::iterator Pool::endActive()
{
return end();
}
template
inline typename Pool::iterator Pool::beginInactive()
{
return end();
}
template
inline typename Pool::iterator Pool::endInactive()
{
return container.end();
}
template
inline typename Pool::const_iterator Pool::begin() const
{
return container.begin();
}
template
inline typename Pool::const_iterator Pool::end() const
{
return container.begin() + nbActive;
}
template
inline typename Pool::const_iterator Pool::beginActive() const
{
return begin();
}
template
inline typename Pool::const_iterator Pool::endActive() const
{
return end();
}
template
inline typename Pool::const_iterator Pool::beginInactive() const
{
return end();
}
template
inline typename Pool::const_iterator Pool::endInactive() const
{
return container.end();
}
template
inline typename Pool::reverse_iterator Pool::rbegin()
{
return container.rbegin();
}
template
inline typename Pool::reverse_iterator Pool::rend()
{
return container.rbegin() + nbActive;
}
template
inline typename Pool::reverse_iterator Pool::rbeginActive()
{
return rbegin();
}
template
inline typename Pool::reverse_iterator Pool::rendActive()
{
return rend();
}
template
inline typename Pool::reverse_iterator Pool::rbeginInactive()
{
return rend();
}
template
inline typename Pool::reverse_iterator Pool::rendInactive()
{
return container.rend();
}
template
inline typename Pool::const_reverse_iterator Pool::rbegin() const
{
return container.rbegin();
}
template
inline typename Pool::const_reverse_iterator Pool::rend() const
{
return container.rbegin() + nbActive;
}
template
inline typename Pool::const_reverse_iterator Pool::rbeginActive() const
{
return rbegin();
}
template
inline typename Pool::const_reverse_iterator Pool::rendActive() const
{
return rend();
}
template
inline typename Pool::const_reverse_iterator Pool::rbeginInactive() const
{
return rend();
}
template
inline typename Pool::const_reverse_iterator Pool::rendInactive() const
{
return container.rend();
}
template
inline T& Pool::front()
{
return container.front();
}
template
inline T& Pool::back()
{
return container[nbActive - 1];
}
template
inline T& Pool::frontActive()
{
return front();
}
template
inline T& Pool::backActive()
{
return back();
}
template
inline T& Pool::frontInactive()
{
return container[nbActive];
}
template
inline T& Pool::backInactive()
{
return container.back();
}
template
inline const T& Pool::front() const
{
return container.front();
}
template
inline const T& Pool::back() const
{
return container[nbActive - 1];
}
template
inline const T& Pool::frontActive() const
{
return front();
}
template
inline const T& Pool::backActive() const
{
return back();
}
template
inline const T& Pool::frontInactive() const
{
return container[nbActive];
}
template
inline const T& Pool::backInactive() const
{
return container.back();
}
template
inline void Pool::assign(T& value)
{
container.insert(container.end(),getNbEmpty(),value);
}
template
inline void Pool::swapElements(T& a,T& b)
{
std::swap(a,b);
}
template
bool Pool::pushActive(T& element)
{
if (container.size() == container.capacity())
return false;
container.push_back(element);
swapElements(container[nbActive],container.back());
++nbActive;
if (container.size() > maxTotal)
maxTotal = container.size();
return true;
}
template
bool Pool::pushInactive(T& element)
{
if (container.size() == container.capacity())
return false;
container.push_back(element);
if (container.size() > maxTotal)
maxTotal = container.size();
return true;
}
template
void Pool::makeInactive(size_t index)
{
if (index >= nbActive)
return;
swapElements(container[index],container[nbActive - 1]);
--nbActive;
}
template
inline void Pool::makeAllInactive()
{
nbActive = 0;
}
template
T* Pool::makeActive()
{
if (getNbInactive() == 0)
return NULL;
++nbActive;
return &container[0] + nbActive - 1;
}
template
T* Pool::makeActive(size_t index)
{
if (getNbInactive() < index)
return NULL;
swapElements(container[nbActive],container[nbActive + index]);
++nbActive;
return &container[0] + nbActive - 1;
}
template
void Pool::erase(size_t index)
{
if (index >= container.size())
return;
if (index < nbActive)
{
swapElements(container[index],container[nbActive - 1]);
--nbActive;
index = nbActive;
}
swapElements(container[index],container.back());
container.pop_back();
}
template
void Pool::clear()
{
container.clear();
nbActive = 0;
}
template
inline void Pool::reallocate(size_t capacity)
{
container.reserve(capacity);
}
}
#endif