////////////////////////////////////////////////////////////////////////////////// // 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 : * * 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