File indexing completed on 2025-06-01 03:50:40
0001 /* 0002 * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 0003 * 0004 * This software is provided 'as-is', without any express or implied 0005 * warranty. In no event will the authors be held liable for any damages 0006 * arising from the use of this software. 0007 * Permission is granted to anyone to use this software for any purpose, 0008 * including commercial applications, and to alter it and redistribute it 0009 * freely, subject to the following restrictions: 0010 * 1. The origin of this software must not be misrepresented; you must not 0011 * claim that you wrote the original software. If you use this software 0012 * in a product, an acknowledgment in the product documentation would be 0013 * appreciated but is not required. 0014 * 2. Altered source versions must be plainly marked as such, and must not be 0015 * misrepresented as being the original software. 0016 * 3. This notice may not be removed or altered from any source distribution. 0017 */ 0018 0019 #include <Box2D/Common/b2BlockAllocator.h> 0020 #include <cstdlib> 0021 #include <climits> 0022 #include <cstring> 0023 #include <memory> 0024 using namespace std; 0025 0026 int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = 0027 { 0028 16, // 0 0029 32, // 1 0030 64, // 2 0031 96, // 3 0032 128, // 4 0033 160, // 5 0034 192, // 6 0035 224, // 7 0036 256, // 8 0037 320, // 9 0038 384, // 10 0039 448, // 11 0040 512, // 12 0041 640, // 13 0042 }; 0043 uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1]; 0044 bool b2BlockAllocator::s_blockSizeLookupInitialized; 0045 0046 struct b2Chunk 0047 { 0048 int32 blockSize; 0049 b2Block* blocks; 0050 }; 0051 0052 struct b2Block 0053 { 0054 b2Block* next; 0055 }; 0056 0057 b2BlockAllocator::b2BlockAllocator() 0058 { 0059 b2Assert(b2_blockSizes < UCHAR_MAX); 0060 0061 m_chunkSpace = b2_chunkArrayIncrement; 0062 m_chunkCount = 0; 0063 m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); 0064 0065 memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); 0066 memset(m_freeLists, 0, sizeof(m_freeLists)); 0067 0068 if (s_blockSizeLookupInitialized == false) 0069 { 0070 int32 j = 0; 0071 for (int32 i = 1; i <= b2_maxBlockSize; ++i) 0072 { 0073 b2Assert(j < b2_blockSizes); 0074 if (i <= s_blockSizes[j]) 0075 { 0076 s_blockSizeLookup[i] = (uint8)j; 0077 } 0078 else 0079 { 0080 ++j; 0081 s_blockSizeLookup[i] = (uint8)j; 0082 } 0083 } 0084 0085 s_blockSizeLookupInitialized = true; 0086 } 0087 } 0088 0089 b2BlockAllocator::~b2BlockAllocator() 0090 { 0091 for (int32 i = 0; i < m_chunkCount; ++i) 0092 { 0093 b2Free(m_chunks[i].blocks); 0094 } 0095 0096 b2Free(m_chunks); 0097 } 0098 0099 void* b2BlockAllocator::Allocate(int32 size) 0100 { 0101 if (size == 0) 0102 return NULL; 0103 0104 b2Assert(0 < size); 0105 0106 if (size > b2_maxBlockSize) 0107 { 0108 return b2Alloc(size); 0109 } 0110 0111 int32 index = s_blockSizeLookup[size]; 0112 b2Assert(0 <= index && index < b2_blockSizes); 0113 0114 if (m_freeLists[index]) 0115 { 0116 b2Block* block = m_freeLists[index]; 0117 m_freeLists[index] = block->next; 0118 return block; 0119 } 0120 else 0121 { 0122 if (m_chunkCount == m_chunkSpace) 0123 { 0124 b2Chunk* oldChunks = m_chunks; 0125 m_chunkSpace += b2_chunkArrayIncrement; 0126 m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); 0127 memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk)); 0128 memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk)); 0129 b2Free(oldChunks); 0130 } 0131 0132 b2Chunk* chunk = m_chunks + m_chunkCount; 0133 chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize); 0134 #if defined(_DEBUG) 0135 memset(chunk->blocks, 0xcd, b2_chunkSize); 0136 #endif 0137 int32 blockSize = s_blockSizes[index]; 0138 chunk->blockSize = blockSize; 0139 int32 blockCount = b2_chunkSize / blockSize; 0140 b2Assert(blockCount * blockSize <= b2_chunkSize); 0141 for (int32 i = 0; i < blockCount - 1; ++i) 0142 { 0143 b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i); 0144 b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1)); 0145 block->next = next; 0146 } 0147 b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1)); 0148 last->next = NULL; 0149 0150 m_freeLists[index] = chunk->blocks->next; 0151 ++m_chunkCount; 0152 0153 return chunk->blocks; 0154 } 0155 } 0156 0157 void b2BlockAllocator::Free(void* p, int32 size) 0158 { 0159 if (size == 0) 0160 { 0161 return; 0162 } 0163 0164 b2Assert(0 < size); 0165 0166 if (size > b2_maxBlockSize) 0167 { 0168 b2Free(p); 0169 return; 0170 } 0171 0172 int32 index = s_blockSizeLookup[size]; 0173 b2Assert(0 <= index && index < b2_blockSizes); 0174 0175 #ifdef _DEBUG 0176 // Verify the memory address and size is valid. 0177 int32 blockSize = s_blockSizes[index]; 0178 bool found = false; 0179 for (int32 i = 0; i < m_chunkCount; ++i) 0180 { 0181 b2Chunk* chunk = m_chunks + i; 0182 if (chunk->blockSize != blockSize) 0183 { 0184 b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks || 0185 (int8*)chunk->blocks + b2_chunkSize <= (int8*)p); 0186 } 0187 else 0188 { 0189 if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize) 0190 { 0191 found = true; 0192 } 0193 } 0194 } 0195 0196 b2Assert(found); 0197 0198 memset(p, 0xfd, blockSize); 0199 #endif 0200 0201 b2Block* block = (b2Block*)p; 0202 block->next = m_freeLists[index]; 0203 m_freeLists[index] = block; 0204 } 0205 0206 void b2BlockAllocator::Clear() 0207 { 0208 for (int32 i = 0; i < m_chunkCount; ++i) 0209 { 0210 b2Free(m_chunks[i].blocks); 0211 } 0212 0213 m_chunkCount = 0; 0214 memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); 0215 0216 memset(m_freeLists, 0, sizeof(m_freeLists)); 0217 }