b2BlockAllocator.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. * 1. The origin of this software must not be misrepresented; you must not
  11. * claim that you wrote the original software. If you use this software
  12. * in a product, an acknowledgment in the product documentation would be
  13. * appreciated but is not required.
  14. * 2. Altered source versions must be plainly marked as such, and must not be
  15. * misrepresented as being the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include <Box2D/Common/b2BlockAllocator.h>
  19. #include <limits.h>
  20. #include <memory.h>
  21. #include <stddef.h>
  22. #include <string.h>
  23. int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] =
  24. {
  25. 16, // 0
  26. 32, // 1
  27. 64, // 2
  28. 96, // 3
  29. 128, // 4
  30. 160, // 5
  31. 192, // 6
  32. 224, // 7
  33. 256, // 8
  34. 320, // 9
  35. 384, // 10
  36. 448, // 11
  37. 512, // 12
  38. 640, // 13
  39. };
  40. uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
  41. bool b2BlockAllocator::s_blockSizeLookupInitialized;
  42. struct b2Chunk
  43. {
  44. int32 blockSize;
  45. b2Block* blocks;
  46. };
  47. struct b2Block
  48. {
  49. b2Block* next;
  50. };
  51. b2BlockAllocator::b2BlockAllocator()
  52. {
  53. b2Assert(b2_blockSizes < UCHAR_MAX);
  54. m_chunkSpace = b2_chunkArrayIncrement;
  55. m_chunkCount = 0;
  56. m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
  57. memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
  58. memset(m_freeLists, 0, sizeof(m_freeLists));
  59. if (s_blockSizeLookupInitialized == false)
  60. {
  61. int32 j = 0;
  62. for (int32 i = 1; i <= b2_maxBlockSize; ++i)
  63. {
  64. b2Assert(j < b2_blockSizes);
  65. if (i <= s_blockSizes[j])
  66. {
  67. s_blockSizeLookup[i] = (uint8)j;
  68. }
  69. else
  70. {
  71. ++j;
  72. s_blockSizeLookup[i] = (uint8)j;
  73. }
  74. }
  75. s_blockSizeLookupInitialized = true;
  76. }
  77. }
  78. b2BlockAllocator::~b2BlockAllocator()
  79. {
  80. for (int32 i = 0; i < m_chunkCount; ++i)
  81. {
  82. b2Free(m_chunks[i].blocks);
  83. }
  84. b2Free(m_chunks);
  85. }
  86. void* b2BlockAllocator::Allocate(int32 size)
  87. {
  88. if (size == 0)
  89. return NULL;
  90. b2Assert(0 < size);
  91. if (size > b2_maxBlockSize)
  92. {
  93. return b2Alloc(size);
  94. }
  95. int32 index = s_blockSizeLookup[size];
  96. b2Assert(0 <= index && index < b2_blockSizes);
  97. if (m_freeLists[index])
  98. {
  99. b2Block* block = m_freeLists[index];
  100. m_freeLists[index] = block->next;
  101. return block;
  102. }
  103. else
  104. {
  105. if (m_chunkCount == m_chunkSpace)
  106. {
  107. b2Chunk* oldChunks = m_chunks;
  108. m_chunkSpace += b2_chunkArrayIncrement;
  109. m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
  110. memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
  111. memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
  112. b2Free(oldChunks);
  113. }
  114. b2Chunk* chunk = m_chunks + m_chunkCount;
  115. chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
  116. #if defined(_DEBUG)
  117. memset(chunk->blocks, 0xcd, b2_chunkSize);
  118. #endif
  119. int32 blockSize = s_blockSizes[index];
  120. chunk->blockSize = blockSize;
  121. int32 blockCount = b2_chunkSize / blockSize;
  122. b2Assert(blockCount * blockSize <= b2_chunkSize);
  123. for (int32 i = 0; i < blockCount - 1; ++i)
  124. {
  125. b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
  126. b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
  127. block->next = next;
  128. }
  129. b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
  130. last->next = NULL;
  131. m_freeLists[index] = chunk->blocks->next;
  132. ++m_chunkCount;
  133. return chunk->blocks;
  134. }
  135. }
  136. void b2BlockAllocator::Free(void* p, int32 size)
  137. {
  138. if (size == 0)
  139. {
  140. return;
  141. }
  142. b2Assert(0 < size);
  143. if (size > b2_maxBlockSize)
  144. {
  145. b2Free(p);
  146. return;
  147. }
  148. int32 index = s_blockSizeLookup[size];
  149. b2Assert(0 <= index && index < b2_blockSizes);
  150. #ifdef _DEBUG
  151. // Verify the memory address and size is valid.
  152. int32 blockSize = s_blockSizes[index];
  153. bool found = false;
  154. for (int32 i = 0; i < m_chunkCount; ++i)
  155. {
  156. b2Chunk* chunk = m_chunks + i;
  157. if (chunk->blockSize != blockSize)
  158. {
  159. b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks ||
  160. (int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
  161. }
  162. else
  163. {
  164. if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
  165. {
  166. found = true;
  167. }
  168. }
  169. }
  170. b2Assert(found);
  171. memset(p, 0xfd, blockSize);
  172. #endif
  173. b2Block* block = (b2Block*)p;
  174. block->next = m_freeLists[index];
  175. m_freeLists[index] = block;
  176. }
  177. void b2BlockAllocator::Clear()
  178. {
  179. for (int32 i = 0; i < m_chunkCount; ++i)
  180. {
  181. b2Free(m_chunks[i].blocks);
  182. }
  183. m_chunkCount = 0;
  184. memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
  185. memset(m_freeLists, 0, sizeof(m_freeLists));
  186. }