@@ -6,6 +6,7 @@ bool IZ_ListFindFilterAlwaysTrue(IZ_ListNode* _node, u64 _index) { | |||||
void IZ_ListInitialize(IZ_List* list) { | void IZ_ListInitialize(IZ_List* list) { | ||||
list->root = NULL; | list->root = NULL; | ||||
list->length = 0; | |||||
} | } | ||||
void IZ_ListTeardown(IZ_List* list) { | void IZ_ListTeardown(IZ_List* list) { | ||||
@@ -27,6 +28,7 @@ IZ_ListNode* IZ_ListAppendNode(IZ_List* list, void* node_value) { | |||||
last_node->next = new_node; | last_node->next = new_node; | ||||
} | } | ||||
new_node->next = NULL; | new_node->next = NULL; | ||||
list->length += 1; | |||||
return new_node; | return new_node; | ||||
} | } | ||||
@@ -53,6 +55,7 @@ void _IZ_ListDeleteFirstNode(IZ_List* list, IZ_ListFindFilter filter) { | |||||
} | } | ||||
SDL_free(iterator); | SDL_free(iterator); | ||||
list->length -= 1; | |||||
return; | return; | ||||
} while (iterator); | } while (iterator); | ||||
} | } | ||||
@@ -11,6 +11,7 @@ typedef struct IZ_ListNode { | |||||
typedef struct { | typedef struct { | ||||
IZ_ListNode* root; | IZ_ListNode* root; | ||||
u64 length; | |||||
} IZ_List; | } IZ_List; | ||||
typedef bool IZ_ListFindFilter(IZ_ListNode*, u64); | typedef bool IZ_ListFindFilter(IZ_ListNode*, u64); | ||||
@@ -71,6 +71,7 @@ spec("data") { | |||||
.next = NULL, | .next = NULL, | ||||
}; | }; | ||||
list2.root = &existing_node; | list2.root = &existing_node; | ||||
list2.length = 1; | |||||
} | } | ||||
after_each() { | after_each() { | ||||
@@ -86,6 +87,7 @@ spec("data") { | |||||
mock_is_called(SDL_malloc), | mock_is_called(SDL_malloc), | ||||
"Allocator function not called." | "Allocator function not called." | ||||
); | ); | ||||
check(list.length == 1, "Length mismatch."); | |||||
} | } | ||||
it("appends new node to non-empty list") { | it("appends new node to non-empty list") { | ||||
@@ -98,6 +100,7 @@ spec("data") { | |||||
mock_is_called(SDL_malloc), | mock_is_called(SDL_malloc), | ||||
"Allocator function not called." | "Allocator function not called." | ||||
); | ); | ||||
check(list2.length == 2, "Length mismatch."); | |||||
} | } | ||||
} | } | ||||
@@ -160,6 +163,8 @@ spec("data") { | |||||
!_IZ_ListFindFirstNode(&list, NodeExists), | !_IZ_ListFindFirstNode(&list, NodeExists), | ||||
"Deleted node still present in list." | "Deleted node still present in list." | ||||
); | ); | ||||
check(list.length == 2, "Length mismatch."); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -1,7 +1,7 @@ | |||||
#include "IZ_pool.h" | #include "IZ_pool.h" | ||||
void IZ_PoolInitialize(IZ_Pool* pool, size_t size) { | void IZ_PoolInitialize(IZ_Pool* pool, size_t size) { | ||||
pool->items = &(IZ_List){ .root = NULL }; | |||||
IZ_ListInitialize(&pool->items); | |||||
pool->memory = SDL_malloc(size); | pool->memory = SDL_malloc(size); | ||||
SDL_memset(pool->memory, 0, size); | SDL_memset(pool->memory, 0, size); | ||||
pool->allocated_memory = 0; | pool->allocated_memory = 0; | ||||
@@ -9,7 +9,7 @@ void IZ_PoolInitialize(IZ_Pool* pool, size_t size) { | |||||
pool->max_size = size; | pool->max_size = size; | ||||
} | } | ||||
IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, size_t size, u64 priority) { | |||||
IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, IZ_PoolAllocationArgs args) { | |||||
// 1. check next free allocation for size | // 1. check next free allocation for size | ||||
// 2. if 1. returns non-null, | // 2. if 1. returns non-null, | ||||
@@ -21,20 +21,19 @@ IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, size_t size, u64 priority) { | |||||
// } | // } | ||||
// } | // } | ||||
if (pool->max_size - pool->allocated_memory < size) { | |||||
if (pool->max_size - pool->allocated_memory < args.size) { | |||||
// TODO deallocate memory based from priority | // TODO deallocate memory based from priority | ||||
} | } | ||||
void* pointer = &pool->memory[pool->next_address]; | void* pointer = &pool->memory[pool->next_address]; | ||||
IZ_ListNode* new_item = IZ_ListAppendNode(pool->items, &(IZ_PoolItem) { | |||||
IZ_ListNode* new_item = IZ_ListAppendNode(&pool->items, &(IZ_PoolItem) { | |||||
.pointer = pointer, | .pointer = pointer, | ||||
.size = size, | |||||
.priority = priority, | |||||
.args = args, | |||||
.pool = pool, | .pool = pool, | ||||
}); | }); | ||||
pool->next_address = (pool->next_address + size) % POOL_MAX_SIZE; | |||||
pool->allocated_memory += size; | |||||
pool->next_address = (pool->next_address + args.size) % POOL_MAX_SIZE; | |||||
pool->allocated_memory += args.size; | |||||
return new_item->value; | return new_item->value; | ||||
} | } | ||||
@@ -43,7 +42,7 @@ IZ_LIST_FILTER_FUNCTION(__current_item) bool IZ_PoolGetSameItem(IZ_ListNode* nod | |||||
} | } | ||||
void IZ_PoolDeallocate(IZ_PoolItem* item) { | void IZ_PoolDeallocate(IZ_PoolItem* item) { | ||||
IZ_ListDeleteFirstNode(__current_item, item)(item->pool->items, IZ_PoolGetSameItem); | |||||
IZ_ListDeleteFirstNode(__current_item, item)(&item->pool->items, IZ_PoolGetSameItem); | |||||
} | } | ||||
void IZ_PoolTeardown(IZ_Pool* pool) { | void IZ_PoolTeardown(IZ_Pool* pool) { | ||||
@@ -10,14 +10,19 @@ | |||||
struct IZ_Pool; | struct IZ_Pool; | ||||
typedef struct { | typedef struct { | ||||
void* pointer; | |||||
size_t size; | size_t size; | ||||
u64 priority; | u64 priority; | ||||
u64 timestamp; | |||||
} IZ_PoolAllocationArgs; | |||||
typedef struct { | |||||
void* pointer; | |||||
IZ_PoolAllocationArgs args; | |||||
struct IZ_Pool* pool; | struct IZ_Pool* pool; | ||||
} IZ_PoolItem; | } IZ_PoolItem; | ||||
typedef struct IZ_Pool { | typedef struct IZ_Pool { | ||||
IZ_List* items; | |||||
IZ_List items; | |||||
u64 next_address; | u64 next_address; | ||||
u64 allocated_memory; | u64 allocated_memory; | ||||
size_t max_size; | size_t max_size; | ||||
@@ -26,7 +31,7 @@ typedef struct IZ_Pool { | |||||
void IZ_PoolInitialize(IZ_Pool*, size_t); | void IZ_PoolInitialize(IZ_Pool*, size_t); | ||||
IZ_PoolItem* IZ_PoolAllocate(IZ_Pool*, size_t, u64); | |||||
IZ_PoolItem* IZ_PoolAllocate(IZ_Pool*, IZ_PoolAllocationArgs); | |||||
void IZ_PoolDeallocate(IZ_PoolItem*); | void IZ_PoolDeallocate(IZ_PoolItem*); | ||||
@@ -17,7 +17,7 @@ struct DummyStruct { | |||||
spec("memory") { | spec("memory") { | ||||
describe("pool") { | describe("pool") { | ||||
describe("PoolInitialize") { | |||||
describe("Initialize") { | |||||
static IZ_Pool pool; | static IZ_Pool pool; | ||||
after_each() { | after_each() { | ||||
@@ -53,7 +53,7 @@ spec("memory") { | |||||
} | } | ||||
} | } | ||||
describe("PoolAllocate") { | |||||
describe("Allocate") { | |||||
static IZ_Pool pool; | static IZ_Pool pool; | ||||
after_each() { | after_each() { | ||||
@@ -63,8 +63,17 @@ spec("memory") { | |||||
it("assigns contiguous memory") { | it("assigns contiguous memory") { | ||||
IZ_PoolInitialize(&pool, POOL_MAX_SIZE); | IZ_PoolInitialize(&pool, POOL_MAX_SIZE); | ||||
void* p1 = IZ_PoolAllocate(&pool, sizeof(struct DummyStruct), 0)->pointer; | |||||
void* p2 = IZ_PoolAllocate(&pool, sizeof(u8), 0)->pointer; | |||||
// FIXME: access violation error | |||||
void* p1 = IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(struct DummyStruct), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
})->pointer; | |||||
void* p2 = IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(u8), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
})->pointer; | |||||
check( | check( | ||||
p2 - p1 == sizeof(struct DummyStruct), | p2 - p1 == sizeof(struct DummyStruct), | ||||
@@ -75,9 +84,21 @@ spec("memory") { | |||||
it("ignores previously deallocated items") { | it("ignores previously deallocated items") { | ||||
IZ_PoolInitialize(&pool, POOL_MAX_SIZE); | IZ_PoolInitialize(&pool, POOL_MAX_SIZE); | ||||
void* p1 = IZ_PoolAllocate(&pool, sizeof(struct DummyStruct), 0)->pointer; | |||||
void* p2 = IZ_PoolAllocate(&pool, sizeof(u8), 0)->pointer; | |||||
void* p3 = IZ_PoolAllocate(&pool, sizeof(u8), 0)->pointer; | |||||
void* p1 = IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(struct DummyStruct), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
})->pointer; | |||||
void* p2 = IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(u8), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
})->pointer; | |||||
void* p3 = IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(u8), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
})->pointer; | |||||
IZ_PoolDeallocate(p2); | IZ_PoolDeallocate(p2); | ||||
@@ -90,16 +111,32 @@ spec("memory") { | |||||
it("deallocates old items to make way for new ones when the memory is full") { | it("deallocates old items to make way for new ones when the memory is full") { | ||||
IZ_PoolInitialize(&pool, sizeof(u32)); | IZ_PoolInitialize(&pool, sizeof(u32)); | ||||
IZ_PoolAllocate(&pool, sizeof(u16), 1); | |||||
IZ_PoolAllocate(&pool, sizeof(u8), 0); | |||||
IZ_PoolAllocate(&pool, sizeof(u8), 0); | |||||
IZ_PoolAllocate(&pool, sizeof(u8), 0); | |||||
IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(u16), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
}); | |||||
IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(u8), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
}); | |||||
IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(u8), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
}); | |||||
IZ_PoolAllocate(&pool, (IZ_PoolAllocationArgs){ | |||||
.size = sizeof(u8), | |||||
.priority = 0, | |||||
.timestamp = 0, | |||||
}); | |||||
} | } | ||||
} | } | ||||
describe("PoolDeallocate") {} | |||||
describe("Deallocate") {} | |||||
describe("PoolTeardown") { | |||||
describe("Teardown") { | |||||
static IZ_Pool pool; | static IZ_Pool pool; | ||||
before_each() { | before_each() { | ||||