b2_block_allocator.cpp
Go to the documentation of this file.
1 // MIT License
2 
3 // Copyright (c) 2019 Erin Catto
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
24 #include <limits.h>
25 #include <string.h>
26 #include <stddef.h>
27 
28 static const int32 b2_chunkSize = 16 * 1024;
29 static const int32 b2_maxBlockSize = 640;
30 static const int32 b2_chunkArrayIncrement = 128;
31 
32 // These are the supported object sizes. Actual allocations are rounded up the next size.
34 {
35  16, // 0
36  32, // 1
37  64, // 2
38  96, // 3
39  128, // 4
40  160, // 5
41  192, // 6
42  224, // 7
43  256, // 8
44  320, // 9
45  384, // 10
46  448, // 11
47  512, // 12
48  640, // 13
49 };
50 
51 // This maps an arbitrary allocation size to a suitable slot in b2_blockSizes.
52 struct b2SizeMap
53 {
55  {
56  int32 j = 0;
57  values[0] = 0;
58  for (int32 i = 1; i <= b2_maxBlockSize; ++i)
59  {
61  if (i <= b2_blockSizes[j])
62  {
63  values[i] = (uint8)j;
64  }
65  else
66  {
67  ++j;
68  values[i] = (uint8)j;
69  }
70  }
71  }
72 
74 };
75 
76 static const b2SizeMap b2_sizeMap;
77 
78 struct b2Chunk
79 {
82 };
83 
84 struct b2Block
85 {
87 };
88 
90 {
91  b2Assert(b2_blockSizeCount < UCHAR_MAX);
92 
93  m_chunkSpace = b2_chunkArrayIncrement;
94  m_chunkCount = 0;
95  m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
96 
97  memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
98  memset(m_freeLists, 0, sizeof(m_freeLists));
99 }
100 
102 {
103  for (int32 i = 0; i < m_chunkCount; ++i)
104  {
105  b2Free(m_chunks[i].blocks);
106  }
107 
108  b2Free(m_chunks);
109 }
110 
112 {
113  if (size == 0)
114  {
115  return nullptr;
116  }
117 
118  b2Assert(0 < size);
119 
120  if (size > b2_maxBlockSize)
121  {
122  return b2Alloc(size);
123  }
124 
125  int32 index = b2_sizeMap.values[size];
126  b2Assert(0 <= index && index < b2_blockSizeCount);
127 
128  if (m_freeLists[index])
129  {
130  b2Block* block = m_freeLists[index];
131  m_freeLists[index] = block->next;
132  return block;
133  }
134  else
135  {
136  if (m_chunkCount == m_chunkSpace)
137  {
138  b2Chunk* oldChunks = m_chunks;
139  m_chunkSpace += b2_chunkArrayIncrement;
140  m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
141  memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
142  memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
143  b2Free(oldChunks);
144  }
145 
146  b2Chunk* chunk = m_chunks + m_chunkCount;
147  chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
148 #if defined(_DEBUG)
149  memset(chunk->blocks, 0xcd, b2_chunkSize);
150 #endif
151  int32 blockSize = b2_blockSizes[index];
152  chunk->blockSize = blockSize;
153  int32 blockCount = b2_chunkSize / blockSize;
154  b2Assert(blockCount * blockSize <= b2_chunkSize);
155  for (int32 i = 0; i < blockCount - 1; ++i)
156  {
157  b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
158  b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
159  block->next = next;
160  }
161  b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
162  last->next = nullptr;
163 
164  m_freeLists[index] = chunk->blocks->next;
165  ++m_chunkCount;
166 
167  return chunk->blocks;
168  }
169 }
170 
171 void b2BlockAllocator::Free(void* p, int32 size)
172 {
173  if (size == 0)
174  {
175  return;
176  }
177 
178  b2Assert(0 < size);
179 
180  if (size > b2_maxBlockSize)
181  {
182  b2Free(p);
183  return;
184  }
185 
186  int32 index = b2_sizeMap.values[size];
187  b2Assert(0 <= index && index < b2_blockSizeCount);
188 
189 #if defined(_DEBUG)
190  // Verify the memory address and size is valid.
191  int32 blockSize = b2_blockSizes[index];
192  bool found = false;
193  for (int32 i = 0; i < m_chunkCount; ++i)
194  {
195  b2Chunk* chunk = m_chunks + i;
196  if (chunk->blockSize != blockSize)
197  {
198  b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks ||
199  (int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
200  }
201  else
202  {
203  if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
204  {
205  found = true;
206  }
207  }
208  }
209 
210  b2Assert(found);
211 
212  memset(p, 0xfd, blockSize);
213 #endif
214 
215  b2Block* block = (b2Block*)p;
216  block->next = m_freeLists[index];
217  m_freeLists[index] = block;
218 }
219 
221 {
222  for (int32 i = 0; i < m_chunkCount; ++i)
223  {
224  b2Free(m_chunks[i].blocks);
225  }
226 
227  m_chunkCount = 0;
228  memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
229  memset(m_freeLists, 0, sizeof(m_freeLists));
230 }
void * b2Alloc(int32 size)
Implement this function to use your own memory allocator.
Definition: b2_settings.h:100
const int32 b2_blockSizeCount
static const int32 b2_blockSizes[b2_blockSizeCount]
static const int32 b2_chunkSize
uint8 values[b2_maxBlockSize+1]
static const int32 b2_maxBlockSize
void Free(void *p, int32 size)
Free memory. This will use b2Free if the size is larger than b2_maxBlockSize.
static const int32 b2_chunkArrayIncrement
signed int int32
Definition: b2_types.h:28
void * Allocate(int32 size)
Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize.
static const b2SizeMap b2_sizeMap
b2Block * next
unsigned char uint8
Definition: b2_types.h:29
void b2Free(void *mem)
If you implement b2Alloc, you should also implement this function.
Definition: b2_settings.h:106
b2Block * blocks
signed char int8
Definition: b2_types.h:26
#define b2Assert(A)
Definition: b2_common.h:37


mvsim
Author(s):
autogenerated on Tue Jul 4 2023 03:08:19