diff --git a/CMakeLists.txt b/CMakeLists.txt index a266d70..92c3984 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ add_executable( src/packages/game/input/IZ_keyboard.h src/packages/game/IZ_config.c src/packages/game/IZ_config.h - src/packages/game/geometry/IZ_point2d.c src/packages/game/geometry/IZ_point2d.h src/packages/game/geometry/IZ_vector2d.c src/packages/game/geometry/IZ_vector2d.h src/packages/game/geometry/IZ_rect.c src/packages/game/geometry/IZ_rect.h src/packages/game/core/IZ_object.c src/packages/game/core/IZ_object.h src/packages/game/core/IZ_creature.c src/packages/game/core/IZ_creature.h src/packages/game/core/IZ_entity.c src/packages/game/core/IZ_entity.h src/packages/game/memory/IZ_pool.c src/packages/game/memory/IZ_pool.h src/packages/game/input/IZ_input.c src/packages/game/input/IZ_input.h src/packages/game/input/IZ_midi.c src/packages/game/input/IZ_midi.h) + src/packages/game/geometry/IZ_point2d.c src/packages/game/geometry/IZ_point2d.h src/packages/game/geometry/IZ_vector2d.c src/packages/game/geometry/IZ_vector2d.h src/packages/game/geometry/IZ_rect.c src/packages/game/geometry/IZ_rect.h src/packages/game/core/IZ_object.c src/packages/game/core/IZ_object.h src/packages/game/core/IZ_creature.c src/packages/game/core/IZ_creature.h src/packages/game/core/IZ_entity.c src/packages/game/core/IZ_entity.h src/packages/game/memory/IZ_pool.c src/packages/game/memory/IZ_pool.h src/packages/game/input/IZ_input.c src/packages/game/input/IZ_input.h src/packages/game/input/IZ_midi.c src/packages/game/input/IZ_midi.h src/packages/game/data/IZ_list.c src/packages/game/data/IZ_list.h) target_link_libraries( game @@ -118,7 +118,17 @@ add_executable( src/packages/game/memory/IZ_pool.h src/packages/game/memory/IZ_pool.c - src/packages/game/memory/memory.test.c) + src/packages/game/memory/memory.test.c src/packages/game/data/IZ_list.c src/packages/game/data/IZ_list.h) + +add_executable( + game-test-data + dependencies/bdd-for-c/bdd-for-c.h + src/packages/test/IZ_mock.h + src/packages/test/IZ_test.h + + src/packages/game/data/IZ_list.h + src/packages/game/data/IZ_list.c + src/packages/game/data/data.test.c) if (WIN32) add_custom_command(TARGET game POST_BUILD diff --git a/__mocks__/SDL_stdinc.mock.h b/__mocks__/SDL_stdinc.mock.h index 8e8b099..1f768b1 100644 --- a/__mocks__/SDL_stdinc.mock.h +++ b/__mocks__/SDL_stdinc.mock.h @@ -2,10 +2,23 @@ #define SDL_STDINC_MOCK_H #include +#include "../src/packages/game/IZ_common.h" #include "../src/packages/test/IZ_test.h" mock(SDL_memcpy) void* SDL_memcpy(void* dst, const void* src, size_t len) { mock_return(SDL_memcpy) memcpy(dst, src, len); } +mock(SDL_memset) void* SDL_memset(void* dst, i32 c, size_t len) { + mock_return(SDL_memset) memset(dst, c, len); +} + +mock(SDL_malloc) void* SDL_malloc(size_t size) { + mock_return(SDL_malloc) malloc(size); +} + +mock(SDL_free) void SDL_free(void* mem) { + mock_return(SDL_free); +} + #endif diff --git a/src/packages/game/IZ_app.c b/src/packages/game/IZ_app.c index 6cc128c..4d2810a 100644 --- a/src/packages/game/IZ_app.c +++ b/src/packages/game/IZ_app.c @@ -20,15 +20,7 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app) { } IZ_InputInitialize(config_path, &app->input_state); - IZ_PoolInitialize(&app->pool); -// void* p1 = IZ_PoolAllocate(&app->memory_pool, sizeof(u16), 0)->pointer; -// void* p2 = IZ_PoolAllocate(&app->memory_pool, sizeof(u8), 0)->pointer; -// void* p3 = IZ_PoolAllocate(&app->memory_pool, sizeof(u64), 0)->pointer; -// void* p4 = IZ_PoolAllocate(&app->memory_pool, sizeof(u32), 0)->pointer; -// printf("\n%p %p %p %p\n", p1, p2, p3, p4); -// IZ_PoolDeallocate(p1); -// void* p5 = IZ_PoolAllocate(&app->memory_pool, sizeof(u16), 0)->pointer; -// printf("\n%p\n", p5); + IZ_PoolInitialize(&app->pool, POOL_MAX_SIZE); // TODO put into its timer module app->ticks = 0; diff --git a/src/packages/game/IZ_common.h b/src/packages/game/IZ_common.h index 18ca1d6..d1448e2 100644 --- a/src/packages/game/IZ_common.h +++ b/src/packages/game/IZ_common.h @@ -2,6 +2,7 @@ #define IZ_COMMON_H #include +#include #define PLAYERS (unsigned char) 1 #define APP_NAME "SDL2" diff --git a/src/packages/game/data/IZ_list.c b/src/packages/game/data/IZ_list.c new file mode 100644 index 0000000..66a0a3e --- /dev/null +++ b/src/packages/game/data/IZ_list.c @@ -0,0 +1,77 @@ +#include "IZ_list.h" + +bool IZ_ListFindFilterAlwaysTrue(IZ_ListNode* _node, u64 _index) { + return true; +} + +void IZ_ListInitialize(IZ_List* list) { + list->root = NULL; +} + +void IZ_ListTeardown(IZ_List* list) { + while (list->root) { + _IZ_ListDeleteFirstNode(list, IZ_ListFindFilterAlwaysTrue); + } +} + +IZ_ListNode* IZ_ListAppendNode(IZ_List* list, void* node_value) { + IZ_ListNode* new_node = SDL_malloc(sizeof(IZ_ListNode)); + new_node->value = node_value; + if (!(list->root)) { + list->root = new_node; + } else { + IZ_ListNode *last_node = list->root; + while (last_node->next) { + last_node = last_node->next; + } + last_node->next = new_node; + } + new_node->next = NULL; + return new_node; +} + +void _IZ_ListDeleteFirstNode(IZ_List* list, IZ_ListFindFilter filter) { + if (!(list && list->root)) { + return; + } + + IZ_ListNode* iterator = list->root; + IZ_ListNode* previous_node = NULL; + u64 index = 0; + do { + if (!filter(iterator, index)) { + previous_node = iterator; + iterator = iterator->next; + index += 1; + continue; + } + + if (previous_node) { + previous_node->next = iterator->next; + } else { + list->root = iterator->next; + } + + SDL_free(iterator); + return; + } while (iterator); +} + +IZ_ListNode* _IZ_ListFindFirstNode(IZ_List* list, IZ_ListFindFilter filter) { + if (!(list && list->root)) { + return NULL; + } + + IZ_ListNode* iterator = list->root; + u64 index = 0; + do { + if (!filter(iterator, index)) { + iterator = iterator->next; + index += 1; + continue; + } + return iterator; + } while (iterator); + + return NULL; +} diff --git a/src/packages/game/data/IZ_list.h b/src/packages/game/data/IZ_list.h new file mode 100644 index 0000000..df56aa8 --- /dev/null +++ b/src/packages/game/data/IZ_list.h @@ -0,0 +1,34 @@ +#ifndef IZ_LIST_H +#define IZ_LIST_H + +#include "../IZ_common.h" +#include "SDL_stdinc.h" + +typedef struct IZ_ListNode { + void* value; + struct IZ_ListNode* next; +} IZ_ListNode; + +typedef struct { + IZ_ListNode* root; +} IZ_List; + +typedef bool IZ_ListFindFilter(IZ_ListNode*, u64); + +void IZ_ListInitialize(IZ_List*); + +void IZ_ListTeardown(IZ_List*); + +IZ_ListNode* IZ_ListAppendNode(IZ_List*, void*); + +#define IZ_LIST_FILTER_FUNCTION(X) static IZ_PoolItem* X = NULL; + +void _IZ_ListDeleteFirstNode(IZ_List*, IZ_ListFindFilter); + +#define IZ_ListDeleteFirstNode(X, Y) X = Y; _IZ_ListDeleteFirstNode + +IZ_ListNode* _IZ_ListFindFirstNode(IZ_List*, IZ_ListFindFilter); + +#define IZ_ListFindFirstNode(X, Y) X = Y; _IZ_ListFindFirstNode + +#endif diff --git a/src/packages/game/data/data.test.c b/src/packages/game/data/data.test.c new file mode 100644 index 0000000..65e2f24 --- /dev/null +++ b/src/packages/game/data/data.test.c @@ -0,0 +1,166 @@ +#include "../../test/IZ_test.h" +#include "../../game/IZ_common.h" +#include "../../../__mocks__/SDL_stdinc.mock.h" +#include "IZ_list.h" + +bool NodeExists(IZ_ListNode* node, u64 _index) { + return *((u64*) node->value) == 42069; +} + +bool NodeExists2(IZ_ListNode* node, u64 _index) { + return *((u64*) node->value) == 69420; +} + +bool NodeDoesNotExist(IZ_ListNode* node, u64 _index) { + return *((u64*) node->value) == 55555; +} + +spec("data") { + describe("list") { + describe("Initialize") { + static IZ_List list; + it("sets root to NULL") { + IZ_ListInitialize(&list); + + check(list.root == NULL, "List not properly initialized."); + } + } + + describe("Teardown") { + static IZ_List list; + + before_each() { + static u64 value1 = 69420u; + static u64 value2 = 42069u; + static u64 value3 = 69069u; + + IZ_ListInitialize(&list); + IZ_ListAppendNode(&list, &value1); + IZ_ListAppendNode(&list, &value2); + IZ_ListAppendNode(&list, &value3); + } + + after_each() { + mock_reset(SDL_free); + } + + it("removes all nodes from the list") { + mock_set_expected_calls(SDL_free, 3); + IZ_ListTeardown(&list); + + check( + mock_get_expected_calls(SDL_free) == mock_get_actual_calls(SDL_free), + "Deallocator function call count mismatch." + ); + } + } + + describe("AppendNode") { + static IZ_List list; + static IZ_List list2; + + before_each() { + IZ_ListInitialize(&list); + } + + before_each() { + IZ_ListInitialize(&list2); + static u64 existing_value = 69420u; + static IZ_ListNode existing_node = { + .value = &existing_value, + .next = NULL, + }; + list2.root = &existing_node; + } + + after_each() { + mock_reset(SDL_malloc); + } + + it("appends new node to empty list and sets it as root") { + static u64 value = 69420u; + IZ_ListAppendNode(&list, &value); + + check(*((u64*) list.root->value) == 69420u, "Node not properly appended."); + check( + mock_is_called(SDL_malloc), + "Allocator function not called." + ); + } + + it("appends new node to non-empty list") { + static u64 value1 = 42069u; + + IZ_ListAppendNode(&list2, &value1); + + check(*((u64*) list2.root->next->value) == 42069u, "Node not properly appended."); + check( + mock_is_called(SDL_malloc), + "Allocator function not called." + ); + } + } + + describe("FindFirstNode") { + static IZ_List list; + static u64 value1 = 69420u; + static u64 value2 = 42069u; + + before_each() { + IZ_ListInitialize(&list); + IZ_ListAppendNode(&list, &value1); + IZ_ListAppendNode(&list, &value2); + } + + it("retrieves first node satisfying the filter condition") { + static IZ_ListNode* node; + node = _IZ_ListFindFirstNode(&list, NodeExists); + check(*((u64*) node->value) == 42069u, "Existing node not found."); + } + + it("returns NULL when all nodes do not satisfy the filter condition") { + static IZ_ListNode* node; + node = _IZ_ListFindFirstNode(&list, NodeDoesNotExist); + check(node == NULL, "Non-existing node found."); + } + } + + describe("DeleteFirstNode") { + static IZ_List list; + + before_each() { + static u64 value1 = 69420u; + static u64 value2 = 42069u; + static u64 value3 = 69069u; + + IZ_ListInitialize(&list); + IZ_ListAppendNode(&list, &value1); + IZ_ListAppendNode(&list, &value2); + IZ_ListAppendNode(&list, &value3); + } + + after_each() { + mock_reset(SDL_free); + } + + it("removes first node satisfying the filter condition") { + _IZ_ListDeleteFirstNode(&list, NodeExists); + + check( + mock_is_called(SDL_free), + "Deallocator function not called." + ); + + check( + _IZ_ListFindFirstNode(&list, NodeExists2), + "Node supposed to be present in list is absent." + ); + + check( + !_IZ_ListFindFirstNode(&list, NodeExists), + "Deleted node still present in list." + ); + } + } + } +} diff --git a/src/packages/game/geometry/IZ_point2d.c b/src/packages/game/geometry/IZ_point2d.c index 84caab7..4be59b2 100644 --- a/src/packages/game/geometry/IZ_point2d.c +++ b/src/packages/game/geometry/IZ_point2d.c @@ -1,6 +1,6 @@ #include "IZ_point2d.h" -IZ_Point2D IZ_PointTranslate(IZ_Point2D point, IZ_GeoCoord translate_x, IZ_GeoCoord translate_y) { +IZ_Point2D IZ_Point2DTranslate(IZ_Point2D point, f32 translate_x, f32 translate_y) { return (IZ_Point2D) { .x = point.x + translate_x, .y = point.y + translate_y, diff --git a/src/packages/game/geometry/IZ_point2d.h b/src/packages/game/geometry/IZ_point2d.h index 7e514b4..9718cf1 100644 --- a/src/packages/game/geometry/IZ_point2d.h +++ b/src/packages/game/geometry/IZ_point2d.h @@ -3,13 +3,11 @@ #include "../IZ_common.h" -typedef f32 IZ_GeoCoord; - typedef struct { - IZ_GeoCoord x; - IZ_GeoCoord y; + f32 x; + f32 y; } IZ_Point2D; -IZ_Point2D IZ_PointTranslate(IZ_Point2D, IZ_GeoCoord, IZ_GeoCoord); +IZ_Point2D IZ_Point2DTranslate(IZ_Point2D, f32, f32); #endif diff --git a/src/packages/game/geometry/IZ_rect.h b/src/packages/game/geometry/IZ_rect.h index 747aa74..3733005 100644 --- a/src/packages/game/geometry/IZ_rect.h +++ b/src/packages/game/geometry/IZ_rect.h @@ -5,17 +5,17 @@ #include "IZ_point2d.h" typedef struct { - IZ_GeoCoord left; - IZ_GeoCoord top; - IZ_GeoCoord right; - IZ_GeoCoord bottom; + f32 left; + f32 top; + f32 right; + f32 bottom; } IZ_Bounds; typedef struct { // top left IZ_Point2D pos; - IZ_GeoCoord width; - IZ_GeoCoord height; + f32 width; + f32 height; } IZ_Rect; IZ_Bounds IZ_RectGetBounds(IZ_Rect); diff --git a/src/packages/game/geometry/IZ_vector2d.c b/src/packages/game/geometry/IZ_vector2d.c index 5d86aa4..f33247c 100644 --- a/src/packages/game/geometry/IZ_vector2d.c +++ b/src/packages/game/geometry/IZ_vector2d.c @@ -1,20 +1,20 @@ #include "IZ_vector2d.h" -IZ_Vector2D IZ_VectorAdd(IZ_Vector2D addend, IZ_Vector2D augend) { +IZ_Vector2D IZ_Vector2DAdd(IZ_Vector2D addend, IZ_Vector2D augend) { return (IZ_Vector2D) { .right = addend.right + augend.right, .up = addend.up + augend.up, }; } -IZ_Vector2D IZ_VectorMultiply(IZ_Vector2D multiplicand, IZ_Vector2D multiplier) { +IZ_Vector2D IZ_Vector2DMultiply(IZ_Vector2D multiplicand, IZ_Vector2D multiplier) { return (IZ_Vector2D) { .right = multiplicand.right * multiplier.right, .up = multiplicand.up * multiplier.up, }; } -IZ_Vector2D IZ_VectorScale(IZ_Vector2D vector, IZ_GeoCoord scalar) { +IZ_Vector2D IZ_Vector2DScale(IZ_Vector2D vector, f32 scalar) { return (IZ_Vector2D) { .right = vector.right * scalar, .up = vector.up * scalar, diff --git a/src/packages/game/geometry/IZ_vector2d.h b/src/packages/game/geometry/IZ_vector2d.h index 35580cf..53676be 100644 --- a/src/packages/game/geometry/IZ_vector2d.h +++ b/src/packages/game/geometry/IZ_vector2d.h @@ -4,14 +4,14 @@ #include "IZ_point2d.h" typedef struct { - IZ_GeoCoord right; - IZ_GeoCoord up; + f32 right; + f32 up; } IZ_Vector2D; -IZ_Vector2D IZ_VectorAdd(IZ_Vector2D, IZ_Vector2D); +IZ_Vector2D IZ_Vector2DAdd(IZ_Vector2D, IZ_Vector2D); -IZ_Vector2D IZ_VectorMultiply(IZ_Vector2D, IZ_Vector2D); +IZ_Vector2D IZ_Vector2DMultiply(IZ_Vector2D, IZ_Vector2D); -IZ_Vector2D IZ_VectorScale(IZ_Vector2D, IZ_GeoCoord); +IZ_Vector2D IZ_Vector2DScale(IZ_Vector2D, f32); #endif diff --git a/src/packages/game/geometry/geometry.test.c b/src/packages/game/geometry/geometry.test.c index 778bf77..f219cf9 100644 --- a/src/packages/game/geometry/geometry.test.c +++ b/src/packages/game/geometry/geometry.test.c @@ -5,7 +5,7 @@ spec("geometry") { describe("point2d") { - describe("PointTranslate") { + describe("Translate") { it("translates coordinates of a point") { static IZ_Point2D input = { .x = 420.f, @@ -18,7 +18,7 @@ spec("geometry") { }; static IZ_Point2D actual; - actual = IZ_PointTranslate(input, 6.f, 9.f); + actual = IZ_Point2DTranslate(input, 6.f, 9.f); check(expected.x == actual.x, "X values do not match."); check(expected.y == actual.y, "Y values do not match."); @@ -27,7 +27,7 @@ spec("geometry") { } describe("vector2d") { - describe("VectorAdd") { + describe("Add") { it("adds two vectors") { static IZ_Vector2D addend = { .right = 420.f, @@ -45,14 +45,14 @@ spec("geometry") { }; static IZ_Vector2D actual_sum; - actual_sum = IZ_VectorAdd(addend, augend); + actual_sum = IZ_Vector2DAdd(addend, augend); check(expected_sum.right == actual_sum.right, "Right values do not match."); check(expected_sum.up == actual_sum.up, "Up values do not match."); } } - describe("VectorMultiply") { + describe("Multiply") { it("multiplies two vectors") { static IZ_Vector2D multiplicand = { .right = 6.f, @@ -70,14 +70,14 @@ spec("geometry") { }; static IZ_Vector2D actual_product; - actual_product = IZ_VectorMultiply(multiplicand, multiplier); + actual_product = IZ_Vector2DMultiply(multiplicand, multiplier); check(expected_product.right == actual_product.right, "Right values do not match."); check(expected_product.up == actual_product.up, "Up values do not match."); } } - describe("VectorScale") { + describe("Scale") { it("scales a vector") { static IZ_Vector2D v = { .right = 420.f, @@ -92,7 +92,7 @@ spec("geometry") { }; static IZ_Vector2D actual; - actual = IZ_VectorScale(v, s); + actual = IZ_Vector2DScale(v, s); check(expected.right == actual.right, "Right values do not match."); check(expected.up == actual.up, "Up values do not match."); @@ -101,7 +101,7 @@ spec("geometry") { } describe("rect") { - describe("RectGetBounds") { + describe("GetBounds") { it("returns the bounds of a rectangle") { static IZ_Rect r = { .pos = { @@ -129,7 +129,7 @@ spec("geometry") { } } - describe("RectBoundsContainPoint") { + describe("BoundsContainPoint") { it("returns true for points inside bounds") { static IZ_Bounds b = { .left = 50, @@ -185,7 +185,7 @@ spec("geometry") { } } - describe("RectBoundsCollide") { + describe("BoundsCollide") { it("returns true for bounds A inside bounds B") { static IZ_Bounds a = { .left = 100, diff --git a/src/packages/game/input/input.test.c b/src/packages/game/input/input.test.c index 5ce5b4a..ef6eace 100644 --- a/src/packages/game/input/input.test.c +++ b/src/packages/game/input/input.test.c @@ -15,7 +15,7 @@ i16 GenerateAxisValueOutsideThreshold(u16 threshold) { spec("input") { describe("joystick") { - describe("JoystickHandleEvents") { + describe("HandleEvents") { static SDL_Event e; static IZ_JoystickState state[PLAYERS] = {}; static IZ_Action action[PLAYERS] = {}; @@ -259,7 +259,7 @@ spec("input") { } } - describe("JoystickSaveConfig") { + describe("SaveConfig") { static IZ_JoystickState state[PLAYERS]; after_each() { @@ -290,7 +290,7 @@ spec("input") { } describe("keyboard") { - describe("KeyboardHandleEvents") { + describe("HandleEvents") { static SDL_Event e; static IZ_KeyboardState state[PLAYERS] = {}; static IZ_Action action[PLAYERS] = {}; @@ -326,7 +326,7 @@ spec("input") { } } - describe("KeyboardSaveConfig") { + describe("SaveConfig") { static IZ_KeyboardState state[PLAYERS] = {}; after_each() { diff --git a/src/packages/game/memory/IZ_pool.c b/src/packages/game/memory/IZ_pool.c index 9b314d5..0003d89 100644 --- a/src/packages/game/memory/IZ_pool.c +++ b/src/packages/game/memory/IZ_pool.c @@ -1,14 +1,15 @@ #include "IZ_pool.h" -void IZ_PoolInitialize(IZ_Pool* pool) { - SDL_memset(pool->items, 0, POOL_MAX_ITEMS * sizeof(IZ_PoolItem)); - pool->top = 0; - pool->memory = SDL_malloc(POOL_MAX_SIZE); - SDL_memset(pool->memory, 0, POOL_MAX_SIZE); +void IZ_PoolInitialize(IZ_Pool* pool, size_t size) { + pool->items = &(IZ_List){ .root = NULL }; + pool->memory = SDL_malloc(size); + SDL_memset(pool->memory, 0, size); + pool->allocated_memory = 0; pool->next_address = 0; + pool->max_size = size; } -IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, size_t size, u64 created_at) { +IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, size_t size, u64 priority) { // 1. check next free allocation for size // 2. if 1. returns non-null, @@ -20,31 +21,29 @@ IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, size_t size, u64 created_at) { // } // } + if (pool->max_size - pool->allocated_memory < size) { + // TODO deallocate memory based from priority + } + void* pointer = &pool->memory[pool->next_address]; - IZ_PoolItem* next_allocation = &pool->items[pool->top]; - pool->items[pool->top] = (IZ_PoolItem) { + IZ_ListNode* new_item = IZ_ListAppendNode(pool->items, &(IZ_PoolItem) { .pointer = pointer, .size = size, - .created_at = created_at, + .priority = priority, .pool = pool, - }; - pool->top = (pool->top + 1) % POOL_MAX_ITEMS; + }); + pool->next_address = (pool->next_address + size) % POOL_MAX_SIZE; - return next_allocation; + pool->allocated_memory += size; + return new_item->value; +} + +IZ_LIST_FILTER_FUNCTION(__current_item) bool IZ_PoolGetSameItem(IZ_ListNode* node, u64 _index) { + return node->value == __current_item; } void IZ_PoolDeallocate(IZ_PoolItem* item) { - u64 i; - for (i = 0; i < POOL_MAX_ITEMS; i += 1) { - if (&item->pool->items[i] != item) { - continue; - } - item->pool->items[i].pool = NULL; - item->pool->items[i].size = 0; - item->pool->items[i].pointer = NULL; - item->pool->items[i].created_at = 0; - return; - } + IZ_ListDeleteFirstNode(__current_item, item)(item->pool->items, IZ_PoolGetSameItem); } void IZ_PoolTeardown(IZ_Pool* pool) { diff --git a/src/packages/game/memory/IZ_pool.h b/src/packages/game/memory/IZ_pool.h index abec363..1f659a9 100644 --- a/src/packages/game/memory/IZ_pool.h +++ b/src/packages/game/memory/IZ_pool.h @@ -3,8 +3,8 @@ #include #include "../IZ_common.h" +#include "../data/IZ_list.h" -#define POOL_MAX_ITEMS (1000) // 16 million allocations max #define POOL_MAX_SIZE (1l << 23) // 16MB struct IZ_Pool; @@ -12,18 +12,19 @@ struct IZ_Pool; typedef struct { void* pointer; size_t size; - u64 created_at; + u64 priority; struct IZ_Pool* pool; } IZ_PoolItem; typedef struct IZ_Pool { - u16 top; + IZ_List* items; u64 next_address; - IZ_PoolItem items[POOL_MAX_ITEMS]; + u64 allocated_memory; + size_t max_size; void* memory; } IZ_Pool; -void IZ_PoolInitialize(IZ_Pool*); +void IZ_PoolInitialize(IZ_Pool*, size_t); IZ_PoolItem* IZ_PoolAllocate(IZ_Pool*, size_t, u64); diff --git a/src/packages/game/memory/memory.test.c b/src/packages/game/memory/memory.test.c index 41451d4..3481e51 100644 --- a/src/packages/game/memory/memory.test.c +++ b/src/packages/game/memory/memory.test.c @@ -1,18 +1,123 @@ #include "../../test/IZ_test.h" +#include "../../../__mocks__/SDL_stdinc.mock.h" #include "IZ_pool.h" +struct DummyInnerStruct { + i8 f; + i8 g; +}; + +struct DummyStruct { + i8 a; + i16 b; + i32 c; + i64 d; + struct DummyInnerStruct e; +}; + spec("memory") { describe("pool") { describe("PoolInitialize") { + static IZ_Pool pool; + + after_each() { + mock_reset(SDL_memset); + } + + after_each() { + mock_reset(SDL_malloc); + } + + after_each() { + IZ_PoolTeardown(&pool); + } + + it("initializes the pool values") { + mock_set_expected_calls(SDL_memset, 1); + IZ_PoolInitialize(&pool, POOL_MAX_SIZE); + + check( + mock_get_expected_calls(SDL_memset) == mock_get_actual_calls(SDL_memset), + "Call count mismatch." + ); + } + + it("initializes the pool memory") { + IZ_PoolInitialize(&pool, POOL_MAX_SIZE); + + check( + mock_is_called(SDL_malloc), + "Memory not allocated." + ); + } } describe("PoolAllocate") { + static IZ_Pool pool; + + after_each() { + IZ_PoolTeardown(&pool); + } + + it("assigns contiguous memory") { + 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; + + check( + p2 - p1 == sizeof(struct DummyStruct), + "Allocated memory mismatch." + ); + } + + it("ignores previously deallocated items") { + 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; + + IZ_PoolDeallocate(p2); + + check( + p3 - p1 == sizeof(struct DummyStruct) + sizeof(u8), + "Allocated memory mismatch." + ); + } + + it("deallocates old items to make way for new ones when the memory is full") { + 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); + } } - describe("PoolDeallocate") { + describe("PoolDeallocate") {} + + describe("PoolTeardown") { + static IZ_Pool pool; + + before_each() { + IZ_PoolInitialize(&pool, POOL_MAX_SIZE); + } + + after_each() { + mock_reset(SDL_free); + } + + it("frees memory") { + IZ_PoolTeardown(&pool); + check( + mock_is_called(SDL_free), + "Memory not freed." + ); + } } } } diff --git a/src/packages/game/output/output.test.c b/src/packages/game/output/output.test.c index 11ffa33..63a0029 100644 --- a/src/packages/game/output/output.test.c +++ b/src/packages/game/output/output.test.c @@ -5,7 +5,7 @@ spec("output") { describe("video") { - describe("VideoSaveConfig") { + describe("SaveConfig") { static IZ_VideoConfig config; after_each() {