The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
4.9KB

  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 "b2BlockAllocator.h"
  19. using namespace std;
  20. int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] =
  21. {
  22. 16, // 0
  23. 32, // 1
  24. 64, // 2
  25. 96, // 3
  26. 128, // 4
  27. 160, // 5
  28. 192, // 6
  29. 224, // 7
  30. 256, // 8
  31. 320, // 9
  32. 384, // 10
  33. 448, // 11
  34. 512, // 12
  35. 640, // 13
  36. };
  37. uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
  38. bool b2BlockAllocator::s_blockSizeLookupInitialized;
  39. struct b2Chunk
  40. {
  41. int32 blockSize;
  42. b2Block* blocks;
  43. };
  44. struct b2Block
  45. {
  46. b2Block* next;
  47. };
  48. b2BlockAllocator::b2BlockAllocator()
  49. {
  50. b2Assert(b2_blockSizes < UCHAR_MAX);
  51. m_chunkSpace = b2_chunkArrayIncrement;
  52. m_chunkCount = 0;
  53. m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
  54. memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
  55. memset(m_freeLists, 0, sizeof(m_freeLists));
  56. if (s_blockSizeLookupInitialized == false)
  57. {
  58. int32 j = 0;
  59. for (int32 i = 1; i <= b2_maxBlockSize; ++i)
  60. {
  61. b2Assert(j < b2_blockSizes);
  62. if (i <= s_blockSizes[j])
  63. {
  64. s_blockSizeLookup[i] = (uint8)j;
  65. }
  66. else
  67. {
  68. ++j;
  69. s_blockSizeLookup[i] = (uint8)j;
  70. }
  71. }
  72. s_blockSizeLookupInitialized = true;
  73. }
  74. }
  75. b2BlockAllocator::~b2BlockAllocator()
  76. {
  77. for (int32 i = 0; i < m_chunkCount; ++i)
  78. {
  79. b2Free(m_chunks[i].blocks);
  80. }
  81. b2Free(m_chunks);
  82. }
  83. void* b2BlockAllocator::Allocate(int32 size)
  84. {
  85. if (size == 0)
  86. return NULL;
  87. b2Assert(0 < size);
  88. if (size > b2_maxBlockSize)
  89. {
  90. return b2Alloc(size);
  91. }
  92. int32 index = s_blockSizeLookup[size];
  93. b2Assert(0 <= index && index < b2_blockSizes);
  94. if (m_freeLists[index])
  95. {
  96. b2Block* block = m_freeLists[index];
  97. m_freeLists[index] = block->next;
  98. return block;
  99. }
  100. else
  101. {
  102. if (m_chunkCount == m_chunkSpace)
  103. {
  104. b2Chunk* oldChunks = m_chunks;
  105. m_chunkSpace += b2_chunkArrayIncrement;
  106. m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
  107. memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
  108. memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
  109. b2Free(oldChunks);
  110. }
  111. b2Chunk* chunk = m_chunks + m_chunkCount;
  112. chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
  113. #if defined(_DEBUG)
  114. memset(chunk->blocks, 0xcd, b2_chunkSize);
  115. #endif
  116. int32 blockSize = s_blockSizes[index];
  117. chunk->blockSize = blockSize;
  118. int32 blockCount = b2_chunkSize / blockSize;
  119. b2Assert(blockCount * blockSize <= b2_chunkSize);
  120. for (int32 i = 0; i < blockCount - 1; ++i)
  121. {
  122. b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
  123. b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
  124. block->next = next;
  125. }
  126. b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
  127. last->next = NULL;
  128. m_freeLists[index] = chunk->blocks->next;
  129. ++m_chunkCount;
  130. return chunk->blocks;
  131. }
  132. }
  133. void b2BlockAllocator::Free(void* p, int32 size)
  134. {
  135. if (size == 0)
  136. {
  137. return;
  138. }
  139. b2Assert(0 < size);
  140. if (size > b2_maxBlockSize)
  141. {
  142. b2Free(p);
  143. return;
  144. }
  145. int32 index = s_blockSizeLookup[size];
  146. b2Assert(0 <= index && index < b2_blockSizes);
  147. #ifdef _DEBUG
  148. // Verify the memory address and size is valid.
  149. int32 blockSize = s_blockSizes[index];
  150. bool found = false;
  151. for (int32 i = 0; i < m_chunkCount; ++i)
  152. {
  153. b2Chunk* chunk = m_chunks + i;
  154. if (chunk->blockSize != blockSize)
  155. {
  156. b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks ||
  157. (int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
  158. }
  159. else
  160. {
  161. if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
  162. {
  163. found = true;
  164. }
  165. }
  166. }
  167. b2Assert(found);
  168. memset(p, 0xfd, blockSize);
  169. #endif
  170. b2Block* block = (b2Block*)p;
  171. block->next = m_freeLists[index];
  172. m_freeLists[index] = block;
  173. }
  174. void b2BlockAllocator::Clear()
  175. {
  176. for (int32 i = 0; i < m_chunkCount; ++i)
  177. {
  178. b2Free(m_chunks[i].blocks);
  179. }
  180. m_chunkCount = 0;
  181. memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
  182. memset(m_freeLists, 0, sizeof(m_freeLists));
  183. }