From bf5b0916e8bb171305288f2183fe6a91dcebbaf7 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 19 Jan 2016 18:29:13 +1100 Subject: [PATCH] pool: capacity queries, comments --- pool.hpp | 14 ++++++---- pool.ipp | 85 +++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 71 insertions(+), 28 deletions(-) diff --git a/pool.hpp b/pool.hpp index a8ef973b..f4aed52c 100644 --- a/pool.hpp +++ b/pool.hpp @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2011-2012 Danny Robson + * Copyright 2011-2016 Danny Robson */ #ifndef __UTIL_POOL_HPP @@ -26,13 +26,15 @@ namespace util { class pool : public nocopy { protected: union node { + node *_node; char _data[sizeof (T)]; - node *_chain; }; - node *m_head; - node *m_next; - size_t m_capacity; + node *m_head; // root address of allocation + node *m_next; // next available entry in the linked list + + const size_t m_capacity; + size_t m_remain; public: pool (unsigned int _capacity); @@ -45,6 +47,8 @@ namespace util { void release (T *data); size_t capacity (void) const; + size_t remain (void) const; + bool empty (void) const; // Indexing size_t index (const T*) const; diff --git a/pool.ipp b/pool.ipp index e559ab04..f9261c33 100644 --- a/pool.ipp +++ b/pool.ipp @@ -11,82 +11,121 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2011-2012 Danny Robson + * Copyright 2011-2016 Danny Robson */ #ifdef __UTIL_POOL_IPP -#error Double inclusion of pool.ipp +#error #endif #define __UTIL_POOL_IPP namespace util { + //------------------------------------------------------------------------- template pool::pool (unsigned int _capacity): - m_capacity (_capacity) + m_capacity (_capacity), + m_remain (_capacity) { static_assert (sizeof (T) >= sizeof (uintptr_t), "pool's chained block system requires that T be at least pointer sized"); - m_head = static_cast (operator new (sizeof (T) * m_capacity)); - m_next = m_head; + // allocate the memory and note the base address for deletion in destructor + m_next = m_head = new node[m_capacity]; // static_cast (operator new (sizeof (T) * m_capacity)); + // initialise the linked list of nodes for (unsigned int i = 0; i < m_capacity - 1; ++i) - m_next[i]._chain = &m_next[i + 1]; - m_next[m_capacity - 1]._chain = NULL; + m_next[i]._node = m_next + i + 1; + m_next[m_capacity - 1]._node = nullptr; } + //------------------------------------------------------------------------- template - pool::~pool () { - CHECK (m_next != NULL); - - unsigned int doomed_count = 0; - for (node *cursor = m_next; cursor != NULL; cursor = cursor->_chain) - ++doomed_count; - - CHECK_EQ (doomed_count, m_capacity); - operator delete (m_head); + pool::~pool () + { + // don't check if everything's been returned as pools are often used + // for PODs which don't need to be destructed via calling release. + delete [] m_head; } + //------------------------------------------------------------------------- template size_t pool::capacity (void) const - { return m_capacity; } + { + return m_capacity; + } + //------------------------------------------------------------------------- + template + size_t + pool::remain (void) const + { + return m_remain; + } + + + //------------------------------------------------------------------------- + template + bool + pool::empty (void) const + { + return m_remain == 0; + } + + + //------------------------------------------------------------------------- template template T* - pool::acquire (Args&... args) { + pool::acquire (Args&... args) + { + // double check we have enough capacity left if (!m_next) throw std::bad_alloc (); + CHECK_GT (m_remain, 0); - node *newnext = m_next->_chain; - T *data = (T*)&m_next->_data; + // save what will become the next node shortly. it could be overwritten + // in the constructor we're about to call. + node *newnext = m_next->_node; + T *data = reinterpret_cast (m_next->_data); + // try to construct the returnable object. try { new (data) T (args...); } catch (...) { - m_next->_chain = newnext; + // the constructor may have overwritten the node linkages before + // throwing. fix this up before forwarding the exception. + m_next->_node = newnext; throw; } + // the object is valid. save the new linked list head and bump the + // stats for availability. m_next = newnext; + m_remain--; + return data; } + //------------------------------------------------------------------------- template void - pool::release (T *data) { + pool::release (T *data) + { + CHECK_LT (m_remain, m_capacity); + data->~T(); node *newnode = reinterpret_cast (data); - newnode->_chain = m_next; + newnode->_node = m_next; m_next = newnode; + m_remain++; } }