// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include inline NzMemoryPool::NzMemoryPool(unsigned int blockSize, unsigned int size, bool canGrow) : m_freeCount(size), m_previous(nullptr), m_canGrow(canGrow), m_blockSize(blockSize), m_size(size) { m_pool.reset(new nzUInt8[blockSize * size]); m_freeList.reset(new void*[size]); // Remplissage de la free list for (unsigned int i = 0; i < size; ++i) m_freeList[i] = &m_pool[m_blockSize * (size-i-1)]; } inline NzMemoryPool::NzMemoryPool(NzMemoryPool&& pool) noexcept { operator=(std::move(pool)); } inline NzMemoryPool::NzMemoryPool(NzMemoryPool* pool) : NzMemoryPool(pool->m_blockSize, pool->m_size, pool->m_canGrow) { m_previous = pool; } inline void* NzMemoryPool::Allocate(unsigned int size) { ///DOC: Si la taille est supérieure à celle d'un bloc du pool, l'opérateur new est utilisé if (size <= m_blockSize) { if (m_freeCount > 0) return m_freeList[--m_freeCount]; else if (m_canGrow) { if (!m_next) m_next.reset(new NzMemoryPool(this)); return m_next->Allocate(size); } } return NzOperatorNew(size); } template inline void NzMemoryPool::Delete(T* ptr) { ///DOC: Va appeler le destructeur de l'objet avant de le libérer if (ptr) { ptr->~T(); Free(ptr); } } inline void NzMemoryPool::Free(void* ptr) { ///DOC: Si appelé avec un pointeur ne faisant pas partie du pool, l'opérateur delete est utilisé if (ptr) { // Le pointeur nous appartient-il ? nzUInt8* freePtr = static_cast(ptr); nzUInt8* poolPtr = m_pool.get(); if (freePtr >= poolPtr && freePtr < poolPtr + m_blockSize*m_size) { #if NAZARA_CORE_SAFE if ((freePtr - poolPtr) % m_blockSize != 0) throw std::runtime_error("Invalid pointer (does not point to an element of the pool)"); #endif m_freeList[m_freeCount++] = ptr; // Si nous sommes vide et l'extension d'un autre pool, nous nous suicidons if (m_freeCount == m_size && m_previous && !m_next) { m_previous->m_next.release(); delete this; // Suicide } } else { if (m_next) m_next->Free(ptr); else NzOperatorDelete(ptr); } } } inline unsigned int NzMemoryPool::GetBlockSize() const { return m_blockSize; } inline unsigned int NzMemoryPool::GetFreeBlocks() const { return m_freeCount; } inline unsigned int NzMemoryPool::GetSize() const { return m_size; } template inline T* NzMemoryPool::New(Args&&... args) { ///DOC: Permet de construire un objet directement dans le pook T* object = static_cast(Allocate(sizeof(T))); NzPlacementNew(object, std::forward(args)...); return object; } inline NzMemoryPool& NzMemoryPool::operator=(NzMemoryPool&& pool) noexcept { m_blockSize = pool.m_blockSize; m_canGrow = pool.m_canGrow; m_freeCount = pool.m_freeCount.load(std::memory_order_relaxed); m_freeList = std::move(pool.m_freeList); m_pool = std::move(pool.m_pool); m_previous = pool.m_previous; m_next = std::move(pool.m_next); m_size = pool.m_size; // Si nous avons été créés par un autre pool, nous devons le faire pointer vers nous de nouveau if (m_previous) { m_previous->m_next.release(); m_previous->m_next.reset(this); } return *this; } #include