diff options
Diffstat (limited to 'mem')
-rw-r--r-- | mem/include/mem.h | 4 | ||||
-rw-r--r-- | mem/src/mem.c | 30 | ||||
-rw-r--r-- | mem/test/mem_test.c | 36 |
3 files changed, 41 insertions, 29 deletions
diff --git a/mem/include/mem.h b/mem/include/mem.h index 224b069..3050ba8 100644 --- a/mem/include/mem.h +++ b/mem/include/mem.h | |||
@@ -68,13 +68,13 @@ | |||
68 | /// Allocate a new chunk of N blocks. | 68 | /// Allocate a new chunk of N blocks. |
69 | /// Return a pointer to the first block of the chunk. | 69 | /// Return a pointer to the first block of the chunk. |
70 | /// When there is no space left in the allocator, allocation can either trap | 70 | /// When there is no space left in the allocator, allocation can either trap |
71 | /// (default) or gracefully return 0. Call mem_enable_traps() to toggle this | 71 | /// (default) or gracefully return null. Call mem_enable_traps() to toggle this |
72 | /// behaviour. | 72 | /// behaviour. |
73 | /// New chunks are conveniently zeroed out. | 73 | /// New chunks are conveniently zeroed out. |
74 | #define mem_alloc(MEM, num_blocks) mem_alloc_(&(MEM)->mem, num_blocks) | 74 | #define mem_alloc(MEM, num_blocks) mem_alloc_(&(MEM)->mem, num_blocks) |
75 | 75 | ||
76 | /// Free the chunk. | 76 | /// Free the chunk. |
77 | /// The chunk pointer is conveniently set to 0. | 77 | /// The chunk pointer is conveniently set to null. |
78 | #define mem_free(MEM, CHUNK) mem_free_(&(MEM)->mem, (void**)CHUNK) | 78 | #define mem_free(MEM, CHUNK) mem_free_(&(MEM)->mem, (void**)CHUNK) |
79 | 79 | ||
80 | /// Return a pointer to a chunk given the chunk's handle. | 80 | /// Return a pointer to a chunk given the chunk's handle. |
diff --git a/mem/src/mem.c b/mem/src/mem.c index 4f5e5ef..70648c9 100644 --- a/mem/src/mem.c +++ b/mem/src/mem.c | |||
@@ -46,24 +46,27 @@ void mem_del_(Memory* mem) { | |||
46 | if (mem->dynamic) { | 46 | if (mem->dynamic) { |
47 | if (mem->chunks) { | 47 | if (mem->chunks) { |
48 | free(mem->chunks); | 48 | free(mem->chunks); |
49 | mem->chunks = 0; | 49 | mem->chunks = nullptr; |
50 | } | 50 | } |
51 | if (mem->blocks) { | 51 | if (mem->blocks) { |
52 | free(mem->blocks); | 52 | free(mem->blocks); |
53 | mem->blocks = 0; | 53 | mem->blocks = nullptr; |
54 | } | 54 | } |
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
58 | void mem_clear_(Memory* mem) { | 58 | void mem_clear_(Memory* mem) { |
59 | assert(mem); | 59 | assert(mem); |
60 | mem->next_free_chunk = 0; | 60 | if (mem->num_blocks > 0) { |
61 | memset(mem->blocks, 0, mem->num_blocks * mem->block_size_bytes); | 61 | mem->num_used_blocks = 0; |
62 | memset(mem->chunks, 0, mem->num_blocks * sizeof(Chunk)); | 62 | mem->next_free_chunk = 0; |
63 | 63 | memset(mem->blocks, 0, mem->num_blocks * mem->block_size_bytes); | |
64 | // Initialize the head as one large free chunk. | 64 | memset(mem->chunks, 0, mem->num_blocks * sizeof(Chunk)); |
65 | Chunk* head = &mem->chunks[0]; | 65 | |
66 | head->num_blocks = mem->num_blocks; | 66 | // Initialize the head as one large free chunk. |
67 | Chunk* head = &mem->chunks[0]; | ||
68 | head->num_blocks = mem->num_blocks; | ||
69 | } | ||
67 | } | 70 | } |
68 | 71 | ||
69 | void* mem_alloc_(Memory* mem, size_t num_blocks) { | 72 | void* mem_alloc_(Memory* mem, size_t num_blocks) { |
@@ -113,10 +116,11 @@ void* mem_alloc_(Memory* mem, size_t num_blocks) { | |||
113 | return &mem->blocks[chunk_idx * mem->block_size_bytes]; | 116 | return &mem->blocks[chunk_idx * mem->block_size_bytes]; |
114 | } else { | 117 | } else { |
115 | if (mem->trap) { | 118 | if (mem->trap) { |
116 | FAIL("Memory allocation failed, increase the allocator's capacity or " | 119 | FAIL( |
117 | "avoid fragmentation."); | 120 | "Memory allocation failed, increase the allocator's capacity or " |
121 | "avoid fragmentation."); | ||
118 | } | 122 | } |
119 | return 0; // Large-enough free chunk not found. | 123 | return nullptr; // Large-enough free chunk not found. |
120 | } | 124 | } |
121 | } | 125 | } |
122 | 126 | ||
@@ -172,7 +176,7 @@ void mem_free_(Memory* mem, void** chunk_ptr) { | |||
172 | 176 | ||
173 | mem->num_used_blocks--; | 177 | mem->num_used_blocks--; |
174 | 178 | ||
175 | *chunk_ptr = 0; | 179 | *chunk_ptr = nullptr; |
176 | } | 180 | } |
177 | 181 | ||
178 | // The handle is the chunk's index. We don't call it an index in the public API | 182 | // The handle is the chunk's index. We don't call it an index in the public API |
diff --git a/mem/test/mem_test.c b/mem/test/mem_test.c index 14718a5..52ce5a9 100644 --- a/mem/test/mem_test.c +++ b/mem/test/mem_test.c | |||
@@ -32,6 +32,12 @@ TEST_CASE(mem_create_dyn) { | |||
32 | mem_make_dyn(&mem, NUM_BLOCKS, sizeof(int)); | 32 | mem_make_dyn(&mem, NUM_BLOCKS, sizeof(int)); |
33 | } | 33 | } |
34 | 34 | ||
35 | // Clear an uninitialized allocator. | ||
36 | TEST_CASE(mem_clear_uninitialized) { | ||
37 | test_mem mem = {0}; | ||
38 | mem_clear(&mem); | ||
39 | } | ||
40 | |||
35 | // Allocate N chunks of 1 block each. | 41 | // Allocate N chunks of 1 block each. |
36 | TEST_CASE(mem_fully_allocate) { | 42 | TEST_CASE(mem_fully_allocate) { |
37 | test_mem mem; | 43 | test_mem mem; |
@@ -39,7 +45,7 @@ TEST_CASE(mem_fully_allocate) { | |||
39 | 45 | ||
40 | for (int i = 0; i < NUM_BLOCKS; ++i) { | 46 | for (int i = 0; i < NUM_BLOCKS; ++i) { |
41 | const int* block = mem_alloc(&mem, 1); | 47 | const int* block = mem_alloc(&mem, 1); |
42 | TEST_TRUE(block != 0); | 48 | TEST_TRUE(block != nullptr); |
43 | } | 49 | } |
44 | 50 | ||
45 | TEST_TRUE(mem_size(&mem) == NUM_BLOCKS); | 51 | TEST_TRUE(mem_size(&mem) == NUM_BLOCKS); |
@@ -50,15 +56,15 @@ TEST_CASE(mem_fill_then_free) { | |||
50 | test_mem mem; | 56 | test_mem mem; |
51 | mem_make(&mem); | 57 | mem_make(&mem); |
52 | 58 | ||
53 | int* blocks[NUM_BLOCKS] = {0}; | 59 | int* blocks[NUM_BLOCKS] = {nullptr}; |
54 | for (int i = 0; i < NUM_BLOCKS; i++) { | 60 | for (int i = 0; i < NUM_BLOCKS; i++) { |
55 | blocks[i] = mem_alloc(&mem, 1); | 61 | blocks[i] = mem_alloc(&mem, 1); |
56 | TEST_TRUE(blocks[i] != 0); | 62 | TEST_TRUE(blocks[i] != nullptr); |
57 | } | 63 | } |
58 | 64 | ||
59 | for (int i = 0; i < NUM_BLOCKS; i++) { | 65 | for (int i = 0; i < NUM_BLOCKS; i++) { |
60 | mem_free(&mem, &blocks[i]); | 66 | mem_free(&mem, &blocks[i]); |
61 | TEST_EQUAL(blocks[i], 0); // Pointer should be set to 0 on free. | 67 | TEST_EQUAL(blocks[i], nullptr); // Pointer should be set to 0 on free. |
62 | } | 68 | } |
63 | 69 | ||
64 | TEST_EQUAL(count(&mem), 0); | 70 | TEST_EQUAL(count(&mem), 0); |
@@ -74,12 +80,12 @@ TEST_CASE(mem_allocate_beyond_max_size) { | |||
74 | 80 | ||
75 | // Fully allocate the mem. | 81 | // Fully allocate the mem. |
76 | for (int i = 0; i < NUM_BLOCKS; ++i) { | 82 | for (int i = 0; i < NUM_BLOCKS; ++i) { |
77 | TEST_TRUE(mem_alloc(&mem, 1) != 0); | 83 | TEST_TRUE(mem_alloc(&mem, 1) != nullptr); |
78 | } | 84 | } |
79 | 85 | ||
80 | // Past the end. | 86 | // Past the end. |
81 | for (int i = 0; i < NUM_BLOCKS; ++i) { | 87 | for (int i = 0; i < NUM_BLOCKS; ++i) { |
82 | TEST_EQUAL(mem_alloc(&mem, 1), 0); | 88 | TEST_EQUAL(mem_alloc(&mem, 1), nullptr); |
83 | } | 89 | } |
84 | 90 | ||
85 | TEST_TRUE(mem_size(&mem) == NUM_BLOCKS); | 91 | TEST_TRUE(mem_size(&mem) == NUM_BLOCKS); |
@@ -105,7 +111,7 @@ TEST_CASE(mem_zero_free_block_after_free) { | |||
105 | mem_make(&mem); | 111 | mem_make(&mem); |
106 | 112 | ||
107 | int* val = mem_alloc(&mem, 1); | 113 | int* val = mem_alloc(&mem, 1); |
108 | TEST_TRUE(val != 0); | 114 | TEST_TRUE(val != nullptr); |
109 | *val = 177; | 115 | *val = 177; |
110 | 116 | ||
111 | int* old_val = val; | 117 | int* old_val = val; |
@@ -131,7 +137,7 @@ TEST_CASE(mem_traverse_partially_full) { | |||
131 | 137 | ||
132 | for (int i = 0; i < N; ++i) { | 138 | for (int i = 0; i < N; ++i) { |
133 | int* val = mem_alloc(&mem, 1); | 139 | int* val = mem_alloc(&mem, 1); |
134 | TEST_TRUE(val != 0); | 140 | TEST_TRUE(val != nullptr); |
135 | *val = i + 1; | 141 | *val = i + 1; |
136 | } | 142 | } |
137 | 143 | ||
@@ -146,7 +152,7 @@ TEST_CASE(mem_traverse_full) { | |||
146 | 152 | ||
147 | for (int i = 0; i < NUM_BLOCKS; ++i) { | 153 | for (int i = 0; i < NUM_BLOCKS; ++i) { |
148 | int* val = mem_alloc(&mem, 1); | 154 | int* val = mem_alloc(&mem, 1); |
149 | TEST_TRUE(val != 0); | 155 | TEST_TRUE(val != nullptr); |
150 | *val = i + 1; | 156 | *val = i + 1; |
151 | } | 157 | } |
152 | 158 | ||
@@ -161,7 +167,7 @@ TEST_CASE(mem_get_block) { | |||
161 | 167 | ||
162 | for (int i = 0; i < NUM_BLOCKS; ++i) { | 168 | for (int i = 0; i < NUM_BLOCKS; ++i) { |
163 | int* block = mem_alloc(&mem, 1); | 169 | int* block = mem_alloc(&mem, 1); |
164 | TEST_TRUE(block != 0); | 170 | TEST_TRUE(block != nullptr); |
165 | *block = i; | 171 | *block = i; |
166 | TEST_EQUAL(mem_get_chunk_handle(&mem, block), (size_t)i); | 172 | TEST_EQUAL(mem_get_chunk_handle(&mem, block), (size_t)i); |
167 | } | 173 | } |
@@ -179,7 +185,7 @@ TEST_CASE(mem_fragmentation) { | |||
179 | test_mem mem; | 185 | test_mem mem; |
180 | mem_make(&mem); | 186 | mem_make(&mem); |
181 | 187 | ||
182 | int* blocks[NUM_BLOCKS] = {0}; | 188 | int* blocks[NUM_BLOCKS] = {nullptr}; |
183 | int next_block = 0; | 189 | int next_block = 0; |
184 | 190 | ||
185 | #define ALLOC(num_blocks) \ | 191 | #define ALLOC(num_blocks) \ |
@@ -205,7 +211,7 @@ TEST_CASE(mem_fragmentation) { | |||
205 | 211 | ||
206 | // Should be able to allocate 1 chunk of N blocks. | 212 | // Should be able to allocate 1 chunk of N blocks. |
207 | const void* chunk = mem_alloc(&mem, NUM_BLOCKS); | 213 | const void* chunk = mem_alloc(&mem, NUM_BLOCKS); |
208 | TEST_TRUE(chunk != 0); | 214 | TEST_TRUE(chunk != nullptr); |
209 | } | 215 | } |
210 | 216 | ||
211 | // Clear and re-use an allocator. | 217 | // Clear and re-use an allocator. |
@@ -216,15 +222,17 @@ TEST_CASE(mem_clear_then_reuse) { | |||
216 | // Allocate chunks, contents not important. | 222 | // Allocate chunks, contents not important. |
217 | for (int i = 0; i < NUM_BLOCKS; ++i) { | 223 | for (int i = 0; i < NUM_BLOCKS; ++i) { |
218 | int* chunk = mem_alloc(&mem, 1); | 224 | int* chunk = mem_alloc(&mem, 1); |
219 | TEST_TRUE(chunk != 0); | 225 | TEST_TRUE(chunk != nullptr); |
220 | } | 226 | } |
221 | 227 | ||
222 | mem_clear(&mem); | 228 | mem_clear(&mem); |
229 | TEST_EQUAL(mem_size(&mem), 0); | ||
230 | TEST_EQUAL(mem_capacity(&mem), NUM_BLOCKS); | ||
223 | 231 | ||
224 | // Allocate chunks and assign values 0..N. | 232 | // Allocate chunks and assign values 0..N. |
225 | for (int i = 0; i < NUM_BLOCKS; ++i) { | 233 | for (int i = 0; i < NUM_BLOCKS; ++i) { |
226 | int* chunk = mem_alloc(&mem, 1); | 234 | int* chunk = mem_alloc(&mem, 1); |
227 | TEST_TRUE(chunk != 0); | 235 | TEST_TRUE(chunk != nullptr); |
228 | *chunk = i + 1; | 236 | *chunk = i + 1; |
229 | } | 237 | } |
230 | 238 | ||