diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/AllocationPool.h | 76 | ||||
-rw-r--r-- | src/Chunk.cpp | 4 | ||||
-rw-r--r-- | src/Chunk.h | 3 | ||||
-rw-r--r-- | src/ChunkData.cpp | 48 | ||||
-rw-r--r-- | src/ChunkData.h | 23 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 11 | ||||
-rw-r--r-- | src/ChunkMap.h | 15 |
7 files changed, 143 insertions, 37 deletions
diff --git a/src/AllocationPool.h b/src/AllocationPool.h new file mode 100644 index 000000000..643b44a6d --- /dev/null +++ b/src/AllocationPool.h @@ -0,0 +1,76 @@ + +#pragma once + +#include <memory> + +template<class T, size_t BufferSize> +class cAllocationPool { + public: + + class cStarvationCallbacks + { + public: + virtual ~cStarvationCallbacks() {} + virtual void OnStartingUsingBuffer() = 0; + virtual void OnStopUsingBuffer() = 0; + virtual void OnBufferEmpty() = 0; + }; + + cAllocationPool(std::auto_ptr<cStarvationCallbacks> a_Callbacks) : + m_Callbacks(a_Callbacks) + { + } + + ~cAllocationPool() + { + while (!m_FreeList.empty()) + { + free (m_FreeList.front()); + m_FreeList.pop_front(); + } + } + + T* Allocate() + { + if (m_FreeList.size() <= BufferSize) + { + void * space = malloc(sizeof(T)); + if (space != NULL) + { + return new(space) T; + } + else if (m_FreeList.size() == BufferSize) + { + m_Callbacks->OnStartingUsingBuffer(); + } + else if (m_FreeList.empty()) + { + m_Callbacks->OnBufferEmpty(); + // Try again until the memory is avalable + return Allocate(); + } + } + // placement new, used to initalize the object + T* ret = new (m_FreeList.front()) T; + m_FreeList.pop_front(); + return ret; + } + void Free(T* ptr) + { + if (ptr == NULL) + { + return; + } + // placement destruct. + ptr->~T(); + m_FreeList.push_front(ptr); + if (m_FreeList.size() == BufferSize) + { + m_Callbacks->OnStopUsingBuffer(); + } + } + + private: + std::list<void *> m_FreeList; + std::auto_ptr<cStarvationCallbacks> m_Callbacks; +}; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index e5f8f1e29..5262eb798 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -64,7 +64,8 @@ sSetBlock::sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_Bloc cChunk::cChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World, - cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP + cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, + cAllocationPool<cChunkData::sChunkSection,1600>& a_Pool ) : m_IsValid(false), m_IsLightValid(false), @@ -77,6 +78,7 @@ cChunk::cChunk( m_PosZ(a_ChunkZ), m_World(a_World), m_ChunkMap(a_ChunkMap), + m_ChunkData(a_Pool), m_BlockTickX(0), m_BlockTickY(0), m_BlockTickZ(0), diff --git a/src/Chunk.h b/src/Chunk.h index d95537acf..c7c26333d 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -65,7 +65,8 @@ public: cChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ, // Chunk coords cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects - cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP // Neighbor chunks + cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks + cAllocationPool<cChunkData::sChunkSection,1600>& a_Pool ); cChunk(cChunk & other); ~cChunk(); diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp index 79029f0cf..1bc3072c2 100644 --- a/src/ChunkData.cpp +++ b/src/ChunkData.cpp @@ -6,11 +6,12 @@ #endif #include "ChunkData.h" -cChunkData::cChunkData() +cChunkData::cChunkData(cAllocationPool<cChunkData::sChunkSection, 1600>& a_Pool) : #if __cplusplus < 201103L // auto_ptr style interface for memory management - : IsOwner(true) + IsOwner(true), #endif +m_Pool(a_Pool) { memset(m_Sections, 0, sizeof(m_Sections)); } @@ -34,7 +35,8 @@ cChunkData::~cChunkData() #if __cplusplus < 201103L // auto_ptr style interface for memory management cChunkData::cChunkData(const cChunkData& other) : - IsOwner(true) + IsOwner(true), + m_Pool(other.m_Pool) { for (size_t i = 0; i < CHUNK_SECTION_COUNT; i++) { @@ -60,13 +62,15 @@ cChunkData::~cChunkData() m_Sections[i] = other.m_Sections[i]; } other.IsOwner = false; + ASSERT(&m_Pool == &other.m_Pool); } return *this; } #else // unique_ptr style interface for memory management - cChunkData::cChunkData(cChunkData&& other) + cChunkData::cChunkData(cChunkData&& other) : + m_Pool(other.m_Pool) { for (size_t i = 0; i < CHUNK_SECTION_COUNT; i++) { @@ -79,6 +83,7 @@ cChunkData::~cChunkData() { if (&other != this) { + ASSERT(&m_Pool == &other.m_Pool); for (size_t i = 0; i < CHUNK_SECTION_COUNT; i++) { Free(m_Sections[i]);; @@ -236,8 +241,8 @@ NIBBLETYPE cChunkData::GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const cChunkData cChunkData::Copy() const { - cChunkData copy; - for (size_t i = 0; i < CHUNK_SECTION_COUNT; i++) + cChunkData copy(m_Pool); + for (int i = 0; i < CHUNK_SECTION_NUM; i++) { if (m_Sections[i] != NULL) { @@ -427,7 +432,7 @@ void cChunkData::SetBlocks(const BLOCKTYPE * a_src) void cChunkData::SetMeta(const NIBBLETYPE * a_src) { - for (size_t i = 0; i < CHUNK_SECTION_COUNT; i++) + for (size_t i = 0; i < CHUNK_SECTION_NUM; i++) { const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2; if (m_Sections[i] != NULL) @@ -440,9 +445,6 @@ void cChunkData::SetMeta(const NIBBLETYPE * a_src) } else { - // j counts how many of leading zeros the buffer has - // if j == segment_length then the buffer is all zeros so there is no point - // creating the buffer. size_t j = 0; // do nothing whilst 0 for (; j < segment_length && a_src[i * segment_length + j] == 0; j++); @@ -470,6 +472,11 @@ void cChunkData::SetMeta(const NIBBLETYPE * a_src) sizeof(m_Sections[i]->m_BlockSkyLight) ); } + else + { + Free(m_Sections[i]); + m_Sections[i] = 0; + } } } } @@ -477,10 +484,10 @@ void cChunkData::SetMeta(const NIBBLETYPE * a_src) -void cChunkData::SetBlockLight(const NIBBLETYPE * a_src) +void cChunkData::SetLight(const NIBBLETYPE * a_src) { if (!a_src) return; - for (size_t i = 0; i < CHUNK_SECTION_COUNT; i++) + for (size_t i = 0; i < CHUNK_SECTION_NUM; i++) { const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2; if (m_Sections[i] != NULL) @@ -493,9 +500,6 @@ void cChunkData::SetBlockLight(const NIBBLETYPE * a_src) } else { - // j counts how many of leading zeros the buffer has - // if j == segment_length then the buffer is all zeros so there is no point - // creating the buffer. size_t j = 0; // do nothing whilst 0 for (; j < segment_length && a_src[i * segment_length + j] == 0; j++); @@ -523,6 +527,11 @@ void cChunkData::SetBlockLight(const NIBBLETYPE * a_src) sizeof(m_Sections[i]->m_BlockSkyLight) ); } + else + { + Free(m_Sections[i]); + m_Sections[i] = 0; + } } } } @@ -533,7 +542,7 @@ void cChunkData::SetBlockLight(const NIBBLETYPE * a_src) void cChunkData::SetSkyLight (const NIBBLETYPE * a_src) { if (!a_src) return; - for (size_t i = 0; i < CHUNK_SECTION_COUNT; i++) + for (size_t i = 0; i < CHUNK_SECTION_NUM; i++) { const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2; if (m_Sections[i] != NULL) @@ -546,9 +555,6 @@ void cChunkData::SetSkyLight (const NIBBLETYPE * a_src) } else { - // j counts how many of leading zeros the buffer has - // if j == segment_length then the buffer is all zeros so there is no point - // creating the buffer. size_t j = 0; // do nothing whilst 0 for (; j < segment_length && a_src[i * segment_length + j] == 0xFF; j++); @@ -587,14 +593,14 @@ void cChunkData::SetSkyLight (const NIBBLETYPE * a_src) cChunkData::sChunkSection * cChunkData::Allocate() const { // TODO: use a allocation pool - return new cChunkData::sChunkSection; + return m_Pool.Allocate(); } void cChunkData::Free(cChunkData::sChunkSection * ptr) const { - delete ptr; + m_Pool.Free(ptr); } diff --git a/src/ChunkData.h b/src/ChunkData.h index 16fcc4d37..08f1603bb 100644 --- a/src/ChunkData.h +++ b/src/ChunkData.h @@ -7,6 +7,7 @@ #include "ChunkDef.h" +#include "AllocationPool.h" @@ -20,7 +21,9 @@ class cChunkData { public: - cChunkData(); + struct sChunkSection; + + cChunkData(cAllocationPool<cChunkData::sChunkSection, 1600>& a_Pool); ~cChunkData(); #if __cplusplus < 201103L @@ -54,6 +57,13 @@ public: void SetBlockLight (const NIBBLETYPE * a_src); void SetSkyLight (const NIBBLETYPE * a_src); + struct sChunkSection { + BLOCKTYPE m_BlockTypes [CHUNK_SECTION_HEIGHT * 16 * 16] ; + NIBBLETYPE m_BlockMeta [CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; + NIBBLETYPE m_BlockLight [CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; + NIBBLETYPE m_BlockSkyLight[CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; + }; + private: static const size_t CHUNK_SECTION_HEIGHT = 16; @@ -63,20 +73,15 @@ private: // auto_ptr style interface for memory management mutable bool IsOwner; #endif - - struct sChunkSection { - BLOCKTYPE m_BlockTypes [CHUNK_SECTION_HEIGHT * 16 * 16] ; - NIBBLETYPE m_BlockMeta [CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; - NIBBLETYPE m_BlockLight [CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; - NIBBLETYPE m_BlockSkyLight[CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; - }; - + sChunkSection *m_Sections[CHUNK_SECTION_COUNT]; sChunkSection * Allocate() const; void Free(sChunkSection * ptr) const; void ZeroSection(sChunkSection * ptr) const; + + cAllocationPool<cChunkData::sChunkSection, 1600>& m_Pool; }; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index d3f44bef8..bf2b09342 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -34,7 +34,8 @@ // cChunkMap: cChunkMap::cChunkMap(cWorld * a_World ) - : m_World( a_World ) + : m_World( a_World ), + m_Pool(std::auto_ptr<cAllocationPool<cChunkData::sChunkSection,1600>::cStarvationCallbacks>(new cStarvationCallbacks())) { } @@ -78,7 +79,7 @@ cChunkMap::cChunkLayer * cChunkMap::GetLayer(int a_LayerX, int a_LayerZ) } // Not found, create new: - cChunkLayer * Layer = new cChunkLayer(a_LayerX, a_LayerZ, this); + cChunkLayer * Layer = new cChunkLayer(a_LayerX, a_LayerZ, this, m_Pool); if (Layer == NULL) { LOGERROR("cChunkMap: Cannot create new layer, server out of memory?"); @@ -2646,11 +2647,13 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) //////////////////////////////////////////////////////////////////////////////// // cChunkMap::cChunkLayer: -cChunkMap::cChunkLayer::cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Parent) +cChunkMap::cChunkLayer::cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Parent, + cAllocationPool<cChunkData::sChunkSection,1600>& a_Pool) : m_LayerX( a_LayerX ) , m_LayerZ( a_LayerZ ) , m_Parent( a_Parent ) , m_NumChunksLoaded( 0 ) + , m_Pool(a_Pool) { memset(m_Chunks, 0, sizeof(m_Chunks)); } @@ -2692,7 +2695,7 @@ cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_Ch cChunk * neixp = (LocalX < LAYER_SIZE - 1) ? m_Chunks[Index + 1] : m_Parent->FindChunk(a_ChunkX + 1, a_ChunkZ); cChunk * neizm = (LocalZ > 0) ? m_Chunks[Index - LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX , a_ChunkZ - 1); cChunk * neizp = (LocalZ < LAYER_SIZE - 1) ? m_Chunks[Index + LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX , a_ChunkZ + 1); - m_Chunks[Index] = new cChunk(a_ChunkX, 0, a_ChunkZ, m_Parent, m_Parent->GetWorld(), neixm, neixp, neizm, neizp); + m_Chunks[Index] = new cChunk(a_ChunkX, 0, a_ChunkZ, m_Parent, m_Parent->GetWorld(), neixm, neixp, neizm, neizp, m_Pool); } return m_Chunks[Index]; } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index c3deda088..1744c09d0 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -347,7 +347,8 @@ private: class cChunkLayer { public: - cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Parent); + cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Parent, + cAllocationPool<cChunkData::sChunkSection,1600>& a_Pool); ~cChunkLayer(); /** Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check */ @@ -391,6 +392,16 @@ private: int m_LayerZ; cChunkMap * m_Parent; int m_NumChunksLoaded; + + cAllocationPool<cChunkData::sChunkSection,1600> & m_Pool; + }; + + class cStarvationCallbacks + : public cAllocationPool<cChunkData::sChunkSection,1600>::cStarvationCallbacks + { + virtual void OnStartingUsingBuffer() {} + virtual void OnStopUsingBuffer() {} + virtual void OnBufferEmpty() {} }; typedef std::list<cChunkLayer *> cChunkLayerList; @@ -423,6 +434,8 @@ private: /** The cChunkStay descendants that are currently enabled in this chunkmap */ cChunkStays m_ChunkStays; + cAllocationPool<cChunkData::sChunkSection,1600> m_Pool; + cChunkPtr GetChunk (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Doesn't load, doesn't generate |