Linked List
Added in the first support for a linked list type. It is called a List type in the library. Have tested the functionality and so far all seems good
This commit is contained in:
@@ -2,12 +2,16 @@ cmake_minimum_required(VERSION 3.28.1)
|
||||
|
||||
project(quantum-utils)
|
||||
|
||||
add_compile_options(-g)
|
||||
|
||||
set(quantum-src "./quantum/src/")
|
||||
set(test_stuff-src "./test_stuff/src/")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
add_library(quantum SHARED ${quantum-src}memory/zone.c
|
||||
${quantum-src}logger/logger.c)
|
||||
add_library(
|
||||
quantum SHARED ${quantum-src}memory/zone.c ${quantum-src}logger/logger.c
|
||||
${quantum-src}types/linked_list.c)
|
||||
|
||||
add_executable(test_stuff ${test_stuff-src}main.c)
|
||||
|
||||
target_link_libraries(test_stuff quantum)
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <stddef.h> // size_t definition
|
||||
|
||||
#include "../defines.h"
|
||||
|
||||
typedef struct _Zone Zone;
|
||||
|
||||
Zone *zoneCreate(size_t sizeBytes);
|
||||
|
||||
324
quantum/src/types/linked_list.c
Normal file
324
quantum/src/types/linked_list.c
Normal file
@@ -0,0 +1,324 @@
|
||||
#include "linked_list.h"
|
||||
|
||||
#include "../defines.h"
|
||||
#include "../logger/logger.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct Node {
|
||||
struct Node *next;
|
||||
struct Node *prev;
|
||||
void *data;
|
||||
} Node;
|
||||
|
||||
List listCreate() {
|
||||
List new_list;
|
||||
|
||||
new_list.cur_size = 0;
|
||||
new_list.cur_head = NULL;
|
||||
new_list.cur_tail = NULL;
|
||||
|
||||
return new_list;
|
||||
}
|
||||
|
||||
void listDestroy(List *list) {
|
||||
// First lets make sure we don't have a null pointer passed in
|
||||
if (list == NULL) {
|
||||
QWARN("Null list passed to listDestroy().");
|
||||
return;
|
||||
}
|
||||
|
||||
u64 list_size = list->cur_size;
|
||||
Node *del_node = list->cur_tail;
|
||||
Node *next_node = list->cur_tail->prev;
|
||||
|
||||
while (list_size > 0) {
|
||||
// First we want to free del_node
|
||||
free(del_node);
|
||||
|
||||
// Now we want to set del_node to the next_node to free
|
||||
del_node = next_node;
|
||||
|
||||
// Now we set next_node equal to the del_node's previous node
|
||||
if (next_node->prev != NULL) {
|
||||
next_node = next_node->prev;
|
||||
} else if (next_node->prev == NULL) {
|
||||
next_node->next = NULL;
|
||||
}
|
||||
|
||||
// Now we decrement list_size
|
||||
list_size--;
|
||||
}
|
||||
|
||||
// Now we null out the cur_head and cur_tail of our list
|
||||
list->cur_tail = NULL;
|
||||
list->cur_head = NULL;
|
||||
|
||||
// Now we null out the list and make it point to nothing
|
||||
list = NULL;
|
||||
}
|
||||
|
||||
u64 listSize(const List *list) {
|
||||
if (list != NULL)
|
||||
return list->cur_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *listPeek(List *list) {
|
||||
if (list != NULL && list->cur_size > 0)
|
||||
return list->cur_tail->data;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *listPop(List *list) {
|
||||
if (list == NULL) {
|
||||
QWARN("Null list passed to listPop()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node *pop_node = list->cur_tail;
|
||||
Node *prev_node = list->cur_head == list->cur_tail ? NULL : pop_node->prev;
|
||||
void *data = pop_node->data;
|
||||
|
||||
if (prev_node != NULL)
|
||||
prev_node->next = NULL;
|
||||
|
||||
list->cur_size--;
|
||||
|
||||
list->cur_tail = prev_node;
|
||||
|
||||
free(pop_node);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void listPush(List *list, void *data) {
|
||||
// Allocate the space for our new node
|
||||
Node *new_node = malloc(sizeof(Node));
|
||||
|
||||
// Make sure that we were able to allocate the space, and if not we write an
|
||||
// error and return
|
||||
if (new_node == NULL) {
|
||||
QERROR("Could not allocate space to insert data into list.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the current size of our list is 0
|
||||
if (list->cur_size == 0) {
|
||||
// Set the head and tail pointer to the new node as we are about to have
|
||||
// only 1 element
|
||||
list->cur_tail = new_node;
|
||||
list->cur_head = new_node;
|
||||
|
||||
// Set the next and previous of the new node to NULL as we will only
|
||||
// have 1 element and nothing to point to
|
||||
new_node->next = NULL;
|
||||
new_node->prev = NULL;
|
||||
} else {
|
||||
// Set the next of new_node to NULL as it is the new tail,
|
||||
// and also update prev of new_node to point to the current tail
|
||||
new_node->next = NULL;
|
||||
new_node->prev = list->cur_tail;
|
||||
// Set the next of our current tail to point to the new tail
|
||||
list->cur_tail->next = new_node;
|
||||
}
|
||||
|
||||
// Set the data of the new node to the data we passed in
|
||||
new_node->data = data;
|
||||
|
||||
// Update the list size
|
||||
list->cur_size++;
|
||||
|
||||
// Set the list tail pointer to the new node
|
||||
list->cur_tail = new_node;
|
||||
}
|
||||
|
||||
void *listPeekFromFront(List *list) {
|
||||
if (list != NULL && list->cur_size > 0)
|
||||
return list->cur_head->data;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *listPopFromFront(List *list) {
|
||||
if (list == NULL) {
|
||||
QERROR("Null list passed to listPopFromFront()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node *pop_node = list->cur_head;
|
||||
Node *next_node = list->cur_head == list->cur_tail ? NULL : pop_node->next;
|
||||
void *data = pop_node->data;
|
||||
|
||||
if (next_node != NULL)
|
||||
next_node->next = NULL;
|
||||
|
||||
list->cur_size--;
|
||||
|
||||
list->cur_head = next_node;
|
||||
|
||||
free(pop_node);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void listPushFromFront(List *list, void *data) {
|
||||
// Allocate the space for our new node
|
||||
Node *new_node = malloc(sizeof(Node));
|
||||
|
||||
// Make sure that we were able to allocate the space, and if not we write an
|
||||
// error and return
|
||||
if (new_node == NULL) {
|
||||
QERROR("Could not allocate space to insert data into list.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the current size of our list is 0
|
||||
if (list->cur_size == 0) {
|
||||
// Set the head and tail pointer to the new node as we are about to have
|
||||
// only 1 element
|
||||
list->cur_tail = new_node;
|
||||
list->cur_head = new_node;
|
||||
|
||||
// Set the next and previous of the new node to NULL as we will only
|
||||
// have 1 element and nothing to point to
|
||||
new_node->next = NULL;
|
||||
new_node->prev = NULL;
|
||||
} else {
|
||||
// Set the prev of new_node to NULL as it is the new head,
|
||||
// and also update next of new_node to point to the current head
|
||||
new_node->next = list->cur_head;
|
||||
new_node->prev = NULL;
|
||||
// Set the prev of our current head to point to the new head
|
||||
list->cur_head->prev = new_node;
|
||||
}
|
||||
|
||||
// Set the data of the new node to the data we passed in
|
||||
new_node->data = data;
|
||||
|
||||
// Update the list size
|
||||
list->cur_size++;
|
||||
|
||||
// Set the list head pointer to the new node
|
||||
list->cur_head = new_node;
|
||||
}
|
||||
|
||||
void *listDataAt(List *list, u64 pos) {
|
||||
// Make sure our list isn't NULL or empty, if it is return NULL
|
||||
if (list == NULL || list->cur_size == 0) {
|
||||
QWARN("Null or empty list passed into listDataAt()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Next we want to make sure that our position is in range
|
||||
if (pos < 1 || pos > list->cur_size) {
|
||||
QERROR("Position given is out of range: %" PRId64, pos);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This is the pointer to the node with the data we will be returning
|
||||
Node *data_addr = list->cur_head;
|
||||
|
||||
// This is to keep track of what position in the list we are on
|
||||
u64 counter = 1;
|
||||
|
||||
// While we arent at our position yet
|
||||
while (counter != pos) {
|
||||
// Get the next nodes address
|
||||
data_addr = data_addr->next;
|
||||
// And increment the counter
|
||||
counter++;
|
||||
}
|
||||
|
||||
// Return the data from the node
|
||||
return data_addr->data;
|
||||
}
|
||||
|
||||
void listInsertAt(List *list, u64 pos, void *data) {
|
||||
// If our list is null return.
|
||||
if (list == NULL) {
|
||||
QWARN("A null list was passed into listInsertAt()");
|
||||
return;
|
||||
}
|
||||
|
||||
u64 counter = 1;
|
||||
Node *insert_pos;
|
||||
Node *prev_node;
|
||||
Node *new_node = malloc(sizeof(Node));
|
||||
|
||||
if (list->cur_size == 0) {
|
||||
insert_pos = new_node;
|
||||
new_node->next = NULL;
|
||||
new_node->prev = NULL;
|
||||
pos = 1;
|
||||
} else {
|
||||
insert_pos = list->cur_head;
|
||||
}
|
||||
|
||||
new_node->data = data;
|
||||
|
||||
while (counter != pos) {
|
||||
insert_pos = insert_pos->next;
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (insert_pos->prev != NULL)
|
||||
prev_node = insert_pos->prev;
|
||||
|
||||
if (list->cur_size > 1) {
|
||||
new_node->next = insert_pos;
|
||||
new_node->prev = prev_node;
|
||||
insert_pos->prev = new_node;
|
||||
prev_node->next = new_node;
|
||||
}
|
||||
|
||||
list->cur_size++;
|
||||
}
|
||||
|
||||
void listRemoveAt(List *list, u64 pos) {
|
||||
// If we were passed a null or empty list return
|
||||
if (list == NULL || list->cur_size == 0) {
|
||||
QWARN("A null list was passed into listRemoveAt()");
|
||||
return;
|
||||
}
|
||||
|
||||
// If we give a value that is outside of our list return
|
||||
if (pos < 1 || pos > list->cur_size) {
|
||||
QERROR("An invalid index was passed to listRemoveAt()");
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the node we are going to be removing
|
||||
Node *del_node = list->cur_head;
|
||||
|
||||
// This is a counter to keep our position in the list
|
||||
u64 counter = 1;
|
||||
|
||||
// While we aren't at our position
|
||||
while (counter != pos) {
|
||||
// Set the node to the next node
|
||||
del_node = del_node->next;
|
||||
// And increase the counter
|
||||
counter++;
|
||||
}
|
||||
|
||||
// Now we are at the position we want to delete, so let's get the address of
|
||||
// the next and previous nodes
|
||||
Node *prev_node = del_node->prev;
|
||||
Node *next_node = del_node->next;
|
||||
|
||||
// Now let's update their prev/next values accordingly
|
||||
if (prev_node != NULL || next_node != NULL) {
|
||||
prev_node->next = next_node;
|
||||
next_node->prev = prev_node;
|
||||
}
|
||||
|
||||
// Finally we can free del_node
|
||||
free(del_node);
|
||||
|
||||
// Then we decrement the size of our list
|
||||
list->cur_size--;
|
||||
}
|
||||
24
quantum/src/types/linked_list.h
Normal file
24
quantum/src/types/linked_list.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.h"
|
||||
|
||||
typedef struct Node Node;
|
||||
|
||||
typedef struct List {
|
||||
Node *cur_head;
|
||||
Node *cur_tail;
|
||||
u64 cur_size;
|
||||
} List;
|
||||
|
||||
List listCreate();
|
||||
void listDestroy(List *list);
|
||||
u64 listSize(const List *list);
|
||||
void *listPeek(List *list);
|
||||
void *listPop(List *list);
|
||||
void listPush(List *list, void *data);
|
||||
void *listPeekFromFront(List *list);
|
||||
void *listPopFromFront(List *list);
|
||||
void listPushFromFront(List *list, void *data);
|
||||
void *listDataAt(List *list, u64 pos);
|
||||
void listInsertAt(List *list, u64 pos, void *data);
|
||||
void listRemoveAt(List *list, u64 pos);
|
||||
@@ -1,55 +1,60 @@
|
||||
#include "types/linked_list.h"
|
||||
#include <defines.h>
|
||||
#include <logger/logger.h>
|
||||
#include <memory/zone.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Size of i16: %" PRId16 "\n", sizeof(i16));
|
||||
printf("Size of u16: %" PRIu16 "\n", sizeof(u16));
|
||||
printf("Size of i32: %" PRId32 "\n", sizeof(i32));
|
||||
printf("Size of u32: %" PRIu32 "\n", sizeof(u32));
|
||||
printf("Size of i64: %" PRId64 "\n", sizeof(i64));
|
||||
printf("Size of u64: %" PRIu64 "\n", sizeof(u64));
|
||||
printf("Size of f32: %lu\n", sizeof(f32));
|
||||
printf("Size of f64: %lu\n", sizeof(f64));
|
||||
QINFO("Size of i16: %" PRId16, sizeof(i16));
|
||||
QINFO("Size of u16: %" PRIu16, sizeof(u16));
|
||||
QINFO("Size of i32: %" PRId32, sizeof(i32));
|
||||
QINFO("Size of u32: %" PRIu32, sizeof(u32));
|
||||
QINFO("Size of i64: %" PRId64, sizeof(i64));
|
||||
QINFO("Size of u64: %" PRIu64, sizeof(u64));
|
||||
QINFO("Size of f32: %lu", sizeof(f32));
|
||||
QINFO("Size of f64: %lu", sizeof(f64));
|
||||
|
||||
QFATAL("Test");
|
||||
QERROR("Test");
|
||||
QWARN("Test");
|
||||
QINFO("Test");
|
||||
QDEBUG("Test");
|
||||
QINFO("Creating a List...");
|
||||
List my_list = listCreate();
|
||||
QINFO("Pushing to my_list...")
|
||||
i32 pushVal = 42;
|
||||
listPush(&my_list, &pushVal);
|
||||
i32 peekVal = *(i32 *)listPeek(&my_list);
|
||||
|
||||
printf("\nCreating new zone 4K in size...\n");
|
||||
Zone *test_zone = zoneCreate(4096);
|
||||
QDEBUG("Peeking value off of my_list: %" PRId32, peekVal);
|
||||
|
||||
void *test_alloc = zoneAlloc(test_zone, 4);
|
||||
void *test_alloc2 = zoneAlloc(test_zone, 4);
|
||||
QINFO("Pushing another number to my_list...");
|
||||
i32 pushVal2 = 169420;
|
||||
listPush(&my_list, &pushVal2);
|
||||
peekVal = *(i32 *)listPeek(&my_list);
|
||||
|
||||
printf("Address of test_zone: %p\n", (void *)test_zone);
|
||||
printf("Address of test_alloc: %p\n", test_alloc);
|
||||
printf("Address of test_alloc2: %p\n\n", test_alloc2);
|
||||
QDEBUG("Peeking value off of my_list: %" PRId32, peekVal);
|
||||
|
||||
zoneClear(test_zone);
|
||||
i32 pushVal3 = 69;
|
||||
listPush(&my_list, &pushVal3);
|
||||
QDEBUG("Peeking a 3rd value off of my_list: %" PRId32, peekVal);
|
||||
|
||||
u64 *test_free = zoneAlloc(test_zone, sizeof(u64));
|
||||
i32 popVal = *(i32 *)listPop(&my_list);
|
||||
QDEBUG("Popped a value off of my_list: %" PRId32, popVal);
|
||||
|
||||
printf("Address of test_free: %p\n", (void *)test_free);
|
||||
printf("Freeing test_free...\n");
|
||||
peekVal = *(i32 *)listPeek(&my_list);
|
||||
|
||||
zoneFree(&test_free, sizeof(u64));
|
||||
QDEBUG("Peeking value off of my_list: %" PRId32, peekVal);
|
||||
|
||||
printf("Is test_free NULL: %s\n\n", test_free == NULL ? "true" : "false");
|
||||
i32 insertValue = 80085;
|
||||
|
||||
zoneDestroy(test_zone);
|
||||
QINFO("Inserting a value at position 2.");
|
||||
listInsertAt(&my_list, 2, &insertValue);
|
||||
|
||||
const u64 FOUR_GIGS = (u64)4 * 1024 * 1024 * 1024;
|
||||
QDEBUG("Data at position 2 is: %" PRId32, *(i32 *)listDataAt(&my_list, 2));
|
||||
|
||||
Zone *break_zone = zoneCreate(FOUR_GIGS);
|
||||
QINFO("Removing a value at position 2.");
|
||||
listRemoveAt(&my_list, 2);
|
||||
|
||||
while (zoneAlloc(break_zone, 1024 * 1024 * 1024) != NULL) {
|
||||
}
|
||||
QDEBUG("Data at position 2 is now: %" PRId32,
|
||||
*(i32 *)listDataAt(&my_list, 2));
|
||||
|
||||
zoneDestroy(break_zone);
|
||||
QINFO("Destorying List...");
|
||||
listDestroy(&my_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user