Add memory and data-related implementations for handling game data.feature/data-structs
@@ -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 | |||
@@ -2,10 +2,23 @@ | |||
#define SDL_STDINC_MOCK_H | |||
#include <string.h> | |||
#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 |
@@ -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; | |||
@@ -2,6 +2,7 @@ | |||
#define IZ_COMMON_H | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#define PLAYERS (unsigned char) 1 | |||
#define APP_NAME "SDL2" | |||
@@ -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; | |||
} |
@@ -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 |
@@ -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." | |||
); | |||
} | |||
} | |||
} | |||
} |
@@ -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, | |||
@@ -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 |
@@ -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); | |||
@@ -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, | |||
@@ -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 |
@@ -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, | |||
@@ -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() { | |||
@@ -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) { | |||
@@ -3,8 +3,8 @@ | |||
#include <SDL_stdinc.h> | |||
#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); | |||
@@ -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." | |||
); | |||
} | |||
} | |||
} | |||
} |
@@ -5,7 +5,7 @@ | |||
spec("output") { | |||
describe("video") { | |||
describe("VideoSaveConfig") { | |||
describe("SaveConfig") { | |||
static IZ_VideoConfig config; | |||
after_each() { | |||