/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2019 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #pragma once #include #include BEGIN_ODDLPARSER_NS //------------------------------------------------------------------------------------------------- /// @class TPoolAllocator /// @ingroup CPPCore /// /// @brief This class implements a simple pool-based allocation scheme. /// Initially you have to define its size. Each allocation will be done from this initially created /// pool. You have to release all pooled instances after the usage. /// This allocation scheme is fast and does no call any new-calls during the lifetime of the /// allocator. //------------------------------------------------------------------------------------------------- template class TPoolAllocator { public: TPoolAllocator(); TPoolAllocator(size_t numItems); ~TPoolAllocator(); T *alloc(); void release(); void reserve(size_t size); void clear(); size_t capacity() const; size_t reservedMem() const; size_t freeMem() const; void dumpAllocations(std::string &allocs); void resize(size_t growSize); CPPCORE_NONE_COPYING(TPoolAllocator) private: struct Pool { size_t m_poolsize; T *m_pool; size_t m_currentIdx; Pool *m_next; Pool() : m_poolsize(0u), m_pool(nullptr), m_currentIdx(0u), m_next(nullptr) { // empty } Pool(size_t numItems, Pool *prev) : m_poolsize(numItems), m_pool(nullptr), m_currentIdx(0u), m_next(prev) { m_pool = new T[m_poolsize]; } ~Pool() { delete[] m_pool; m_pool = nullptr; } CPPCORE_NONE_COPYING(Pool) }; Pool *getFreePool() { Pool *current(m_freeList); if (nullptr != m_freeList) { m_freeList = m_freeList->m_next; } return current; } Pool *m_first; Pool *m_current; Pool *m_freeList; size_t m_capacity; }; template inline TPoolAllocator::TPoolAllocator() : m_first(nullptr), m_current(nullptr), m_freeList(nullptr), m_capacity(0L) { // empty } template inline TPoolAllocator::TPoolAllocator(size_t numItems) : m_first(nullptr), m_current(nullptr), m_freeList(nullptr), m_capacity(0L) { m_first = new Pool(numItems); m_capacity += numItems; m_current = m_first; } template inline TPoolAllocator::~TPoolAllocator() { clear(); } template inline T *TPoolAllocator::alloc() { if (nullptr == m_current) { return nullptr; } if (m_current->m_currentIdx == m_current->m_poolsize) { resize(m_current->m_poolsize); } T *ptr(&m_current->m_pool[m_current->m_currentIdx]); m_current->m_currentIdx++; return ptr; } template inline void TPoolAllocator::release() { if (nullptr == m_current) { return; } Pool *current(m_first); while (nullptr != current) { current->m_currentIdx = 0; current = current->m_next; } m_freeList = m_first->m_next; m_current = m_first; } template inline void TPoolAllocator::reserve(size_t size) { clear(); m_first = new Pool(size, nullptr); m_current = m_first; m_current->m_pool = new T[size]; m_current->m_poolsize = size; m_capacity = size; } template inline void TPoolAllocator::clear() { if (nullptr == m_current) { return; } Pool *next(m_first); while (nullptr != next) { Pool *current = next; next = current->m_next; delete current; } m_current = nullptr; m_freeList = nullptr; } template inline size_t TPoolAllocator::capacity() const { return m_capacity; } template inline size_t TPoolAllocator::reservedMem() const { return m_capacity * sizeof(T); } template inline size_t TPoolAllocator::freeMem() const { if (nullptr == m_current) { return 0L; } return (m_current->m_poolsize - m_current->m_currentIdx); } template inline void TPoolAllocator::dumpAllocations(std::string &allocs) { allocs.clear(); allocs += "Number allocations = "; allocs += std::to_string(m_current->m_currentIdx); allocs += "\n"; } template inline void TPoolAllocator::resize(size_t growSize) { if (nullptr != m_current) { if (growSize < m_current->m_poolsize) { return; } } if (nullptr == m_first) { m_first = new Pool(growSize, nullptr); m_current = m_first; m_capacity += m_current->m_poolsize; } else { Pool *pool = getFreePool(); if (nullptr == pool) { pool = new Pool(growSize, nullptr); m_capacity += growSize; } m_current->m_next = pool; m_current = m_current->m_next; } } END_ODDLPARSER_NS