diff options
Diffstat (limited to 'mempool')
-rw-r--r-- | mempool/README.md | 23 | ||||
-rw-r--r-- | mempool/include/mempool.h | 2 | ||||
-rw-r--r-- | mempool/src/mempool.c | 15 | ||||
-rw-r--r-- | mempool/test/mempool_test.c | 24 |
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 | ||
3 | A memory pool implementation. | 3 | A memory pool of fixed-sized blocks with O(1) allocation and deallocation. |
4 | 4 | ||
5 | Each block in the pool is tagged with a boolean value that indicates whether the | 5 | Each block in the pool is tagged with a boolean value that indicates whether the |
6 | block is free or in use. The allocator otherwise maintains little additional | 6 | block is free or in use, as well as a pointer to the next free/used block. |
7 | information. Therefore, some operations have linear-time complexity. | 7 | Blocks thus form two lists, a free list and a used list. The allocator |
8 | Specifically: | 8 | maintains the two lists when allocating/deallocating blocks. |
9 | 9 | ||
10 | - Allocating a block scans the pool for the next free block in linear time. | 10 | The allocator's internal data is stored separately from the block data so that |
11 | - Freeing a block runs in constant time. | 11 | the 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 | ||
15 | The allocator's internal data is also stored separately from the main array of | 13 | Free blocks in the mempool always remain zeroed out for convenience of |
16 | blocks so that the block data remains tightly packed. | 14 | programming and debugging. If the application's data structures are valid when |
17 | 15 | zeroed out, then they do not need to be explicitly initialized. | |
18 | For convenience of programming and debugging, free blocks in the mempool always | ||
19 | remain zeroed out. If your data structures are valid when zeroed out, then you | ||
20 | do 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 | ||
67 | void mempool_clear_(mempool* pool) { | 67 | void 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 | ||
130 | void* mempool_get_block_(const mempool* pool, size_t block_index) { | 131 | void* 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 | ||