b2BlockAllocator.cpp 5.0 KB

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