216 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
| * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
 | |
| *
 | |
| * 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.
 | |
| */
 | |
| 
 | |
| #include "Box2D/Common/b2BlockAllocator.h"
 | |
| #include <limits.h>
 | |
| #include <string.h>
 | |
| #include <stddef.h>
 | |
| 
 | |
| int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = 
 | |
| {
 | |
| 	16,		// 0
 | |
| 	32,		// 1
 | |
| 	64,		// 2
 | |
| 	96,		// 3
 | |
| 	128,	// 4
 | |
| 	160,	// 5
 | |
| 	192,	// 6
 | |
| 	224,	// 7
 | |
| 	256,	// 8
 | |
| 	320,	// 9
 | |
| 	384,	// 10
 | |
| 	448,	// 11
 | |
| 	512,	// 12
 | |
| 	640,	// 13
 | |
| };
 | |
| uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
 | |
| bool b2BlockAllocator::s_blockSizeLookupInitialized;
 | |
| 
 | |
| struct b2Chunk
 | |
| {
 | |
| 	int32 blockSize;
 | |
| 	b2Block* blocks;
 | |
| };
 | |
| 
 | |
| struct b2Block
 | |
| {
 | |
| 	b2Block* next;
 | |
| };
 | |
| 
 | |
| b2BlockAllocator::b2BlockAllocator()
 | |
| {
 | |
| 	b2Assert(b2_blockSizes < UCHAR_MAX);
 | |
| 
 | |
| 	m_chunkSpace = b2_chunkArrayIncrement;
 | |
| 	m_chunkCount = 0;
 | |
| 	m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
 | |
| 	
 | |
| 	memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
 | |
| 	memset(m_freeLists, 0, sizeof(m_freeLists));
 | |
| 
 | |
| 	if (s_blockSizeLookupInitialized == false)
 | |
| 	{
 | |
| 		int32 j = 0;
 | |
| 		for (int32 i = 1; i <= b2_maxBlockSize; ++i)
 | |
| 		{
 | |
| 			b2Assert(j < b2_blockSizes);
 | |
| 			if (i <= s_blockSizes[j])
 | |
| 			{
 | |
| 				s_blockSizeLookup[i] = (uint8)j;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				++j;
 | |
| 				s_blockSizeLookup[i] = (uint8)j;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		s_blockSizeLookupInitialized = true;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| b2BlockAllocator::~b2BlockAllocator()
 | |
| {
 | |
| 	for (int32 i = 0; i < m_chunkCount; ++i)
 | |
| 	{
 | |
| 		b2Free(m_chunks[i].blocks);
 | |
| 	}
 | |
| 
 | |
| 	b2Free(m_chunks);
 | |
| }
 | |
| 
 | |
| void* b2BlockAllocator::Allocate(int32 size)
 | |
| {
 | |
| 	if (size == 0)
 | |
| 		return nullptr;
 | |
| 
 | |
| 	b2Assert(0 < size);
 | |
| 
 | |
| 	if (size > b2_maxBlockSize)
 | |
| 	{
 | |
| 		return b2Alloc(size);
 | |
| 	}
 | |
| 
 | |
| 	int32 index = s_blockSizeLookup[size];
 | |
| 	b2Assert(0 <= index && index < b2_blockSizes);
 | |
| 
 | |
| 	if (m_freeLists[index])
 | |
| 	{
 | |
| 		b2Block* block = m_freeLists[index];
 | |
| 		m_freeLists[index] = block->next;
 | |
| 		return block;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (m_chunkCount == m_chunkSpace)
 | |
| 		{
 | |
| 			b2Chunk* oldChunks = m_chunks;
 | |
| 			m_chunkSpace += b2_chunkArrayIncrement;
 | |
| 			m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
 | |
| 			memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
 | |
| 			memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
 | |
| 			b2Free(oldChunks);
 | |
| 		}
 | |
| 
 | |
| 		b2Chunk* chunk = m_chunks + m_chunkCount;
 | |
| 		chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
 | |
| #if defined(_DEBUG)
 | |
| 		memset(chunk->blocks, 0xcd, b2_chunkSize);
 | |
| #endif
 | |
| 		int32 blockSize = s_blockSizes[index];
 | |
| 		chunk->blockSize = blockSize;
 | |
| 		int32 blockCount = b2_chunkSize / blockSize;
 | |
| 		b2Assert(blockCount * blockSize <= b2_chunkSize);
 | |
| 		for (int32 i = 0; i < blockCount - 1; ++i)
 | |
| 		{
 | |
| 			b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
 | |
| 			b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
 | |
| 			block->next = next;
 | |
| 		}
 | |
| 		b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
 | |
| 		last->next = nullptr;
 | |
| 
 | |
| 		m_freeLists[index] = chunk->blocks->next;
 | |
| 		++m_chunkCount;
 | |
| 
 | |
| 		return chunk->blocks;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void b2BlockAllocator::Free(void* p, int32 size)
 | |
| {
 | |
| 	if (size == 0)
 | |
| 	{
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	b2Assert(0 < size);
 | |
| 
 | |
| 	if (size > b2_maxBlockSize)
 | |
| 	{
 | |
| 		b2Free(p);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	int32 index = s_blockSizeLookup[size];
 | |
| 	b2Assert(0 <= index && index < b2_blockSizes);
 | |
| 
 | |
| #ifdef _DEBUG
 | |
| 	// Verify the memory address and size is valid.
 | |
| 	int32 blockSize = s_blockSizes[index];
 | |
| 	bool found = false;
 | |
| 	for (int32 i = 0; i < m_chunkCount; ++i)
 | |
| 	{
 | |
| 		b2Chunk* chunk = m_chunks + i;
 | |
| 		if (chunk->blockSize != blockSize)
 | |
| 		{
 | |
| 			b2Assert(	(int8*)p + blockSize <= (int8*)chunk->blocks ||
 | |
| 						(int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
 | |
| 			{
 | |
| 				found = true;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	b2Assert(found);
 | |
| 
 | |
| 	memset(p, 0xfd, blockSize);
 | |
| #endif
 | |
| 
 | |
| 	b2Block* block = (b2Block*)p;
 | |
| 	block->next = m_freeLists[index];
 | |
| 	m_freeLists[index] = block;
 | |
| }
 | |
| 
 | |
| void b2BlockAllocator::Clear()
 | |
| {
 | |
| 	for (int32 i = 0; i < m_chunkCount; ++i)
 | |
| 	{
 | |
| 		b2Free(m_chunks[i].blocks);
 | |
| 	}
 | |
| 
 | |
| 	m_chunkCount = 0;
 | |
| 	memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
 | |
| 
 | |
| 	memset(m_freeLists, 0, sizeof(m_freeLists));
 | |
| }
 |