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


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


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


last_node->next = new_node; 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; return &last_node->next;
} }


@@ -107,13 +150,50 @@ IZ_ListNode** IZ_ListFindFirstNode(IZ_List* list, IZ_ListFindPredicate filter) {
list->iterator = &list->root; list->iterator = &list->root;
u64 index = 0; u64 index = 0;
do { 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); } while (*list->iterator);


return NULL; 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. * The iterator for traversing the list.
*/ */
IZ_ListNode** iterator; IZ_ListNode** iterator;
/**
* The custom data for use in matching for the find predicate.
*/
void* find_predicate_userdata;
} IZ_List; } IZ_List;


/**
* Predicate for finding a node in a list.
*/
typedef bool IZ_ListFindPredicate(IZ_ListNode**, u64, IZ_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. * Initializes a list.
*/ */
@@ -54,6 +66,12 @@ void IZ_ListTeardown(IZ_List*);
*/ */
IZ_ListNode** IZ_ListAppendNode(IZ_List*, void*); 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. * 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); 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 #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 IZ_List list;
static u64 value1 = 69420u;
static u64 value2 = 42069u;
static IZ_List list2;


before_each() { before_each() {
IZ_ListInitialize(&list); 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() { after_each() {
IZ_ListTeardown(&list); 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."); 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; 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) { 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,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) { 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 // 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 // FIXME here onwards


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

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


Loading…
Cancel
Save