aboutsummaryrefslogtreecommitdiff
path: root/mempool
diff options
context:
space:
mode:
Diffstat (limited to 'mempool')
-rw-r--r--mempool/README.md23
-rw-r--r--mempool/include/mempool.h2
-rw-r--r--mempool/src/mempool.c15
-rw-r--r--mempool/test/mempool_test.c24
4 files changed, 31 insertions, 33 deletions
diff --git a/mempool/README.md b/mempool/README.md
index ed2935e..7eb950e 100644
--- a/mempool/README.md
+++ b/mempool/README.md
@@ -1,20 +1,15 @@
1# Mempool 1# Mempool
2 2
3A memory pool implementation. 3A memory pool of fixed-sized blocks with O(1) allocation and deallocation.
4 4
5Each block in the pool is tagged with a boolean value that indicates whether the 5Each block in the pool is tagged with a boolean value that indicates whether the
6block is free or in use. The allocator otherwise maintains little additional 6block is free or in use, as well as a pointer to the next free/used block.
7information. Therefore, some operations have linear-time complexity. 7Blocks thus form two lists, a free list and a used list. The allocator
8Specifically: 8maintains the two lists when allocating/deallocating blocks.
9 9
10- Allocating a block scans the pool for the next free block in linear time. 10The allocator's internal data is stored separately from the block data so that
11- Freeing a block runs in constant time. 11the data remains tightly packed.
12- Iterating over the pool's used blocks is linear over the number of blocks in
13 the pool, as opposed to just the number of used blocks.
14 12
15The allocator's internal data is also stored separately from the main array of 13Free blocks in the mempool always remain zeroed out for convenience of
16blocks so that the block data remains tightly packed. 14programming and debugging. If the application's data structures are valid when
17 15zeroed out, then they do not need to be explicitly initialized.
18For convenience of programming and debugging, free blocks in the mempool always
19remain zeroed out. If your data structures are valid when zeroed out, then you
20do not need to explicitly initialize them.
diff --git a/mempool/include/mempool.h b/mempool/include/mempool.h
index 245173b..04d0313 100644
--- a/mempool/include/mempool.h
+++ b/mempool/include/mempool.h
@@ -106,8 +106,8 @@
106/// It is valid to mempool_free() the object at each step of the iteration. 106/// It is valid to mempool_free() the object at each step of the iteration.
107#define mempool_foreach(POOL, ITER, BODY) \ 107#define mempool_foreach(POOL, ITER, BODY) \
108 { \ 108 { \
109 size_t i = (POOL)->pool.used; \
110 if ((POOL)->pool.num_used_blocks > 0) { \ 109 if ((POOL)->pool.num_used_blocks > 0) { \
110 size_t i = (POOL)->pool.used; \
111 do { \ 111 do { \
112 if ((POOL)->pool.block_info[i].used) { \ 112 if ((POOL)->pool.block_info[i].used) { \
113 __typeof__((POOL)->object[0])* ITER = \ 113 __typeof__((POOL)->object[0])* ITER = \
diff --git a/mempool/src/mempool.c b/mempool/src/mempool.c
index 46f1053..c398c4f 100644
--- a/mempool/src/mempool.c
+++ b/mempool/src/mempool.c
@@ -34,7 +34,7 @@ bool mempool_make_(
34 block_info = calloc(num_blocks, sizeof(BlockInfo)); 34 block_info = calloc(num_blocks, sizeof(BlockInfo));
35 blocks = calloc(num_blocks, block_size_bytes); 35 blocks = calloc(num_blocks, block_size_bytes);
36 pool->dynamic = true; 36 pool->dynamic = true;
37 if ((block_info == 0) || (blocks == 0)) { 37 if ((block_info == nullptr) || (blocks == nullptr)) {
38 return false; 38 return false;
39 } 39 }
40 } else { 40 } else {
@@ -55,19 +55,20 @@ void mempool_del_(mempool* pool) {
55 if (pool->dynamic) { 55 if (pool->dynamic) {
56 if (pool->block_info) { 56 if (pool->block_info) {
57 free(pool->block_info); 57 free(pool->block_info);
58 pool->block_info = 0; 58 pool->block_info = nullptr;
59 } 59 }
60 if (pool->blocks) { 60 if (pool->blocks) {
61 free(pool->blocks); 61 free(pool->blocks);
62 pool->blocks = 0; 62 pool->blocks = nullptr;
63 } 63 }
64 } 64 }
65} 65}
66 66
67void mempool_clear_(mempool* pool) { 67void mempool_clear_(mempool* pool) {
68 assert(pool); 68 assert(pool);
69 pool->head = 0; 69 pool->head = 0;
70 pool->used = 0; 70 pool->used = 0;
71 pool->num_used_blocks = 0;
71 memset(pool->blocks, 0, pool->num_blocks * pool->block_size_bytes); 72 memset(pool->blocks, 0, pool->num_blocks * pool->block_size_bytes);
72 memset(pool->block_info, 0, pool->num_blocks * sizeof(BlockInfo)); 73 memset(pool->block_info, 0, pool->num_blocks * sizeof(BlockInfo));
73 init_free_list(pool); 74 init_free_list(pool);
@@ -81,7 +82,7 @@ void* mempool_alloc_(mempool* pool) {
81 if (pool->trap) { 82 if (pool->trap) {
82 FAIL("mempool allocation failed, increase the pool's capacity."); 83 FAIL("mempool allocation failed, increase the pool's capacity.");
83 } 84 }
84 return 0; // Pool is full. 85 return nullptr; // Pool is full.
85 } 86 }
86 87
87 // Allocate the block. 88 // Allocate the block.
@@ -124,7 +125,7 @@ void mempool_free_(mempool* pool, void** block_ptr) {
124 125
125 pool->num_used_blocks--; 126 pool->num_used_blocks--;
126 127
127 *block_ptr = 0; 128 *block_ptr = nullptr;
128} 129}
129 130
130void* mempool_get_block_(const mempool* pool, size_t block_index) { 131void* mempool_get_block_(const mempool* pool, size_t block_index) {
diff --git a/mempool/test/mempool_test.c b/mempool/test/mempool_test.c
index 843f7e7..6d904bc 100644
--- a/mempool/test/mempool_test.c
+++ b/mempool/test/mempool_test.c
@@ -39,7 +39,7 @@ TEST_CASE(mempool_allocate_until_full) {
39 39
40 for (int i = 0; i < NUM_BLOCKS; ++i) { 40 for (int i = 0; i < NUM_BLOCKS; ++i) {
41 const int* block = mempool_alloc(&pool); 41 const int* block = mempool_alloc(&pool);
42 TEST_TRUE(block != 0); 42 TEST_TRUE(block != nullptr);
43 } 43 }
44 44
45 TEST_TRUE(mempool_size(&pool) == NUM_BLOCKS); 45 TEST_TRUE(mempool_size(&pool) == NUM_BLOCKS);
@@ -50,10 +50,10 @@ TEST_CASE(mempool_fill_then_free) {
50 test_pool pool; 50 test_pool pool;
51 mempool_make(&pool); 51 mempool_make(&pool);
52 52
53 int* blocks[NUM_BLOCKS] = {0}; 53 int* blocks[NUM_BLOCKS] = {nullptr};
54 for (int i = 0; i < NUM_BLOCKS; ++i) { 54 for (int i = 0; i < NUM_BLOCKS; ++i) {
55 blocks[i] = mempool_alloc(&pool); 55 blocks[i] = mempool_alloc(&pool);
56 TEST_TRUE(blocks[i] != 0); 56 TEST_TRUE(blocks[i] != nullptr);
57 } 57 }
58 58
59 for (int i = 0; i < NUM_BLOCKS; ++i) { 59 for (int i = 0; i < NUM_BLOCKS; ++i) {
@@ -74,7 +74,7 @@ TEST_CASE(mempool_allocate_beyond_max_size) {
74 74
75 // Fully allocate the pool. 75 // Fully allocate the pool.
76 for (int i = 0; i < NUM_BLOCKS; ++i) { 76 for (int i = 0; i < NUM_BLOCKS; ++i) {
77 TEST_TRUE(mempool_alloc(&pool) != 0); 77 TEST_TRUE(mempool_alloc(&pool) != nullptr);
78 } 78 }
79 79
80 // Past the end. 80 // Past the end.
@@ -105,7 +105,7 @@ TEST_CASE(mempool_zero_free_block_after_free) {
105 mempool_make(&pool); 105 mempool_make(&pool);
106 106
107 int* val = mempool_alloc(&pool); 107 int* val = mempool_alloc(&pool);
108 TEST_TRUE(val != 0); 108 TEST_TRUE(val != nullptr);
109 *val = 177; 109 *val = 177;
110 110
111 int* old_val = val; 111 int* old_val = val;
@@ -131,7 +131,7 @@ TEST_CASE(mempool_traverse_partially_full) {
131 131
132 for (int i = 0; i < N; ++i) { 132 for (int i = 0; i < N; ++i) {
133 int* val = mempool_alloc(&pool); 133 int* val = mempool_alloc(&pool);
134 TEST_TRUE(val != 0); 134 TEST_TRUE(val != nullptr);
135 *val = i + 1; 135 *val = i + 1;
136 } 136 }
137 137
@@ -146,7 +146,7 @@ TEST_CASE(mempool_traverse_full) {
146 146
147 for (int i = 0; i < NUM_BLOCKS; ++i) { 147 for (int i = 0; i < NUM_BLOCKS; ++i) {
148 int* val = mempool_alloc(&pool); 148 int* val = mempool_alloc(&pool);
149 TEST_TRUE(val != 0); 149 TEST_TRUE(val != nullptr);
150 *val = i + 1; 150 *val = i + 1;
151 } 151 }
152 152
@@ -161,7 +161,7 @@ TEST_CASE(mempool_get_block) {
161 161
162 for (int i = 0; i < NUM_BLOCKS; ++i) { 162 for (int i = 0; i < NUM_BLOCKS; ++i) {
163 int* block = mempool_alloc(&pool); 163 int* block = mempool_alloc(&pool);
164 TEST_TRUE(block != 0); 164 TEST_TRUE(block != nullptr);
165 *block = i; 165 *block = i;
166 TEST_EQUAL(mempool_get_block_index(&pool, block), (size_t)i); 166 TEST_EQUAL(mempool_get_block_index(&pool, block), (size_t)i);
167 } 167 }
@@ -178,16 +178,18 @@ TEST_CASE(mem_clear_then_reuse) {
178 178
179 // Allocate chunks, contents not important. 179 // Allocate chunks, contents not important.
180 for (int i = 0; i < NUM_BLOCKS; ++i) { 180 for (int i = 0; i < NUM_BLOCKS; ++i) {
181 int* chunk = mempool_alloc(&mem); 181 const int* chunk = mempool_alloc(&mem);
182 TEST_TRUE(chunk != 0); 182 TEST_TRUE(chunk != nullptr);
183 } 183 }
184 184
185 mempool_clear(&mem); 185 mempool_clear(&mem);
186 TEST_EQUAL(mempool_size(&mem), 0);
187 TEST_EQUAL(mempool_capacity(&mem), NUM_BLOCKS);
186 188
187 // Allocate chunks and assign values 0..N. 189 // Allocate chunks and assign values 0..N.
188 for (int i = 0; i < NUM_BLOCKS; ++i) { 190 for (int i = 0; i < NUM_BLOCKS; ++i) {
189 int* chunk = mempool_alloc(&mem); 191 int* chunk = mempool_alloc(&mem);
190 TEST_TRUE(chunk != 0); 192 TEST_TRUE(chunk != nullptr);
191 *chunk = i + 1; 193 *chunk = i + 1;
192 } 194 }
193 195