Browse Source

Implement list functions

Add the list functions that will be used for memory pools.
feature/data-structs
TheoryOfNekomata 1 year ago
parent
commit
444c34c2d6
5 changed files with 242 additions and 20 deletions
  1. +87
    -7
      src/packages/game/data/IZ_list.c
  2. +28
    -0
      src/packages/game/data/IZ_list.h
  3. +112
    -13
      src/packages/game/data/data.test.c
  4. +13
    -0
      src/packages/game/memory/IZ_pool.c
  5. +2
    -0
      src/packages/game/memory/memory.test.c

+ 87
- 7
src/packages/game/data/IZ_list.c View File

@@ -29,25 +29,68 @@ void IZ_ListTeardown(IZ_List* list) {
/**
* Appends a node to the end of the list.
* @param list - The list to append to.
* @param node_value - The value of the node to append.
* @return Pointer to the newly created node.
*/
IZ_ListNode** IZ_ListAppendNode(IZ_List* list, void* node_value) {
IZ_ListNode* new_node = SDL_malloc(sizeof(IZ_ListNode));
new_node->value = node_value;
new_node->next = NULL;
list->length += 1;

if (!(list->root)) {
list->root = new_node;
list->length += 1;
return &list->root;
}

IZ_ListNode *last_node = list->root;
IZ_ListNode* last_node = list->root;
while (last_node->next) {
last_node = last_node->next;
}

last_node->next = new_node;
list->length += 1;
return &last_node->next;
}

/**
* Inserts a node at the specified index in the list.
* @param list - The list to append to.
* @param node_value - The value of the node to insert.
* @param index - The index to insert the node at.
* @return Pointer to the newly created node.
*/
IZ_ListNode** IZ_ListInsertNodeAtIndex(IZ_List* list, void* node_value, u64 index) {
if (index > list->length) {
// we don't want to go out of bounds
return NULL;
}

IZ_ListNode* new_node = SDL_malloc(sizeof(IZ_ListNode));
new_node->value = node_value;
new_node->next = NULL;

if (!(list->root)) {
list->root = new_node;
list->length += 1;
return &list->root;
}

if (index == 0) {
new_node->next = list->root;
list->root = new_node;
list->length += 1;
return &list->root;
}

IZ_ListNode* last_node = list->root;
for (u64 i = 0; i < index - 1; i += 1) {
last_node = last_node->next;
}

new_node->next = last_node->next;
last_node->next = new_node;
list->length += 1;
return &last_node->next;
}

@@ -107,13 +150,50 @@ IZ_ListNode** IZ_ListFindFirstNode(IZ_List* list, IZ_ListFindPredicate filter) {
list->iterator = &list->root;
u64 index = 0;
do {
if (!filter(list->iterator, index, list)) {
list->iterator = &((*list->iterator)->next);
index += 1;
continue;
if (filter(list->iterator, index, list)) {
return list->iterator;
}
return list->iterator;
list->iterator = &((*list->iterator)->next);
index += 1;
} while (*list->iterator);

return NULL;
}

void IZ_ListFilter(IZ_List* original_list, IZ_ListFindPredicate filter, IZ_List* out_filtered_list) {
// we assume the new list is already initialized
IZ_ListNode* node = original_list->root;
u64 index;
for (index = 0; node; index += 1) {
if (!filter(&node, index, original_list)) {
node = node->next;
continue;
}
IZ_ListAppendNode(out_filtered_list, node->value);
node = node->next;
}
}

void IZ_ListSort(IZ_List* original_list, IZ_ListSortComparatorPredicate sort, IZ_List* out_sorted_list) {
// we assume the new list is already initialized
IZ_ListNode* original_node = original_list->root;
u64 original_index;

for (original_index = 0; original_node; original_index += 1) {
if (!out_sorted_list->root) {
IZ_ListAppendNode(out_sorted_list, original_node->value);
original_node = original_node->next;
continue;
}

IZ_ListNode* sorted_node = out_sorted_list->root;
for (u64 sorted_index = 0; sorted_node; sorted_index += 1) {
if (sort(&original_node, &sorted_node, original_index, original_list) < 0) {
IZ_ListInsertNodeAtIndex(out_sorted_list, original_node->value, sorted_index);
original_node = original_node->next;
break;
}
sorted_node = sorted_node->next;
}
}
}

+ 28
- 0
src/packages/game/data/IZ_list.h View File

@@ -34,10 +34,22 @@ typedef struct {
* The iterator for traversing the list.
*/
IZ_ListNode** iterator;
/**
* The custom data for use in matching for the find predicate.
*/
void* find_predicate_userdata;
} IZ_List;

/**
* Predicate for finding a node in a list.
*/
typedef bool IZ_ListFindPredicate(IZ_ListNode**, u64, IZ_List*);

/**
* Comparator callback for sorting a list. Returns a positive value if a > b, a negative value if a < b, and 0 if a == b.
*/
typedef i64 IZ_ListSortComparatorPredicate(IZ_ListNode**, IZ_ListNode**, u64, IZ_List*);

/**
* Initializes a list.
*/
@@ -54,6 +66,12 @@ void IZ_ListTeardown(IZ_List*);
*/
IZ_ListNode** IZ_ListAppendNode(IZ_List*, void*);

/**
* Inserts a node at the specified index in the list.
* @return Pointer to the newly created node.
*/
IZ_ListNode** IZ_ListInsertNodeAtIndex(IZ_List*, void*, u64);

/**
* Deletes the first node in the list that matches the filter.
*/
@@ -65,4 +83,14 @@ void IZ_ListDeleteFirstNode(IZ_List*, IZ_ListFindPredicate);
*/
IZ_ListNode** IZ_ListFindFirstNode(IZ_List*, IZ_ListFindPredicate);

/**
* Creates a new list that contains the nodes that match the filter.
*/
void IZ_ListFilter(IZ_List*, IZ_ListFindPredicate, IZ_List* out1);

/**
* Creates a new list that contains the sorted nodes from the original list.
*/
void IZ_ListSort(IZ_List*, IZ_ListSortComparatorPredicate, IZ_List* out1);

#endif

+ 112
- 13
src/packages/game/data/data.test.c View File

@@ -117,31 +117,60 @@ spec("data") {
}
}

describe("FindFirstNode") {
describe("InsertNodeAtIndex") {
static IZ_List list;
static u64 value1 = 69420u;
static u64 value2 = 42069u;
static IZ_List list2;

before_each() {
IZ_ListInitialize(&list);
IZ_ListAppendNode(&list, &value1);
IZ_ListAppendNode(&list, &value2);
}

before_each() {
IZ_ListInitialize(&list2);
static u64 existing_value = 69420u;
static IZ_ListNode existing_node = {
.value = &existing_value,
.next = NULL,
};
list2.root = &existing_node;
list2.length = 1;
}

after_each() {
mock_reset(SDL_malloc);
}

after_each() {
IZ_ListTeardown(&list);
}

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.");
after_each() {
IZ_ListTeardown(&list2);
}

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.");
it("inserts new node to empty list and sets it as root") {
static u64 value = 69420u;
IZ_ListInsertNodeAtIndex(&list, &value, 0);

check(*((u64*) list.root->value) == 69420u, "Node not properly appended.");
check(
mock_is_called(SDL_malloc),
"Allocator function not called."
);
check(list.length == 1, "Length mismatch.");
}

it("inserts new node to non-empty list") {
static u64 value1 = 42069u;

IZ_ListInsertNodeAtIndex(&list2, &value1, 0);

check(*((u64*) list2.root->value) == 42069u, "Node not properly appended.");
check(
mock_is_called(SDL_malloc),
"Allocator function not called."
);
check(list2.length == 2, "Length mismatch.");
}
}

@@ -184,5 +213,75 @@ spec("data") {
check(list.length == 2, "Length mismatch.");
}
}

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);
}

after_each() {
IZ_ListTeardown(&list);
}

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("Filter") {
static IZ_List original_list;
static IZ_List filtered_list;

before_each() {
IZ_ListInitialize(&original_list);
IZ_ListInitialize(&filtered_list);
static u64 value1 = 69420u;
static u64 value2 = 42069u;
static u64 value3 = 69069u;
IZ_ListAppendNode(&original_list, &value1);
IZ_ListAppendNode(&original_list, &value2);
IZ_ListAppendNode(&original_list, &value3);
}

it("ensures nodes that satisfy find predicate are present") {
IZ_ListFilter(&original_list, NodeExists, &filtered_list);

check(
IZ_ListFindFirstNode(&filtered_list, NodeExists),
"Node supposed to be present in list is absent."
);

check(filtered_list.length == 1, "Length mismatch.");
}

it("ensures nodes that do not satisfy find predicate are absent") {
IZ_ListFilter(&original_list, NodeDoesNotExist, &filtered_list);

check(
IZ_ListFindFirstNode(&filtered_list, NodeDoesNotExist),
"Node supposed to be absent in list is present."
);

check(filtered_list.length == 0, "Length mismatch.");
}
}

describe("Sort") {

}
}
}

+ 13
- 0
src/packages/game/memory/IZ_pool.c View File

@@ -9,6 +9,12 @@ void IZ_PoolInitialize(IZ_Pool* pool, size_t size) {
pool->max_size = size;
}

bool IZ_PoolFindItemsWithLowerPrecedence(IZ_ListNode** node, u64 index, IZ_List* list) {
IZ_PoolItem* item = (IZ_PoolItem*)(*node)->value;
IZ_PoolAllocationArgs* args = (IZ_PoolAllocationArgs*) list->find_predicate_userdata;
return item->args.priority < args->priority;
}

IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, IZ_PoolAllocationArgs args) {
// 1. check next free allocation for size
// 2. if 1. returns non-null,
@@ -21,7 +27,14 @@ IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, IZ_PoolAllocationArgs args) {
// }
// }

if (pool->max_size < args.size) {
// couldn't allocate anything bigger than the pool
return NULL;
}

if (pool->max_size - pool->allocated_memory < args.size) {
pool->items.find_predicate_userdata = &args;
IZ_ListDeleteFirstNode(&pool->items, IZ_PoolFindItemsWithLowerPrecedence);
// TODO deallocate memory based from priority
}



+ 2
- 0
src/packages/game/memory/memory.test.c View File

@@ -144,6 +144,8 @@ spec("memory") {

// FIXME here onwards

printf("\np1: %p, p2: %p, p3: %p\n", p1, p2, p3);

check(
p3 == p2 + sizeof(u8),
"Free memory not properly utilized."


Loading…
Cancel
Save