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)
|
project(quantum-utils)
|
||||||
|
|
||||||
|
add_compile_options(-g)
|
||||||
|
|
||||||
set(quantum-src "./quantum/src/")
|
set(quantum-src "./quantum/src/")
|
||||||
set(test_stuff-src "./test_stuff/src/")
|
set(test_stuff-src "./test_stuff/src/")
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
add_library(quantum SHARED ${quantum-src}memory/zone.c
|
add_library(
|
||||||
${quantum-src}logger/logger.c)
|
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)
|
add_executable(test_stuff ${test_stuff-src}main.c)
|
||||||
|
|
||||||
target_link_libraries(test_stuff quantum)
|
target_link_libraries(test_stuff quantum)
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include <stddef.h> // size_t definition
|
#include <stddef.h> // size_t definition
|
||||||
|
|
||||||
#include "../defines.h"
|
|
||||||
|
|
||||||
typedef struct _Zone Zone;
|
typedef struct _Zone Zone;
|
||||||
|
|
||||||
Zone *zoneCreate(size_t sizeBytes);
|
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 <defines.h>
|
||||||
#include <logger/logger.h>
|
#include <logger/logger.h>
|
||||||
#include <memory/zone.h>
|
#include <memory/zone.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
printf("Size of i16: %" PRId16 "\n", sizeof(i16));
|
QINFO("Size of i16: %" PRId16, sizeof(i16));
|
||||||
printf("Size of u16: %" PRIu16 "\n", sizeof(u16));
|
QINFO("Size of u16: %" PRIu16, sizeof(u16));
|
||||||
printf("Size of i32: %" PRId32 "\n", sizeof(i32));
|
QINFO("Size of i32: %" PRId32, sizeof(i32));
|
||||||
printf("Size of u32: %" PRIu32 "\n", sizeof(u32));
|
QINFO("Size of u32: %" PRIu32, sizeof(u32));
|
||||||
printf("Size of i64: %" PRId64 "\n", sizeof(i64));
|
QINFO("Size of i64: %" PRId64, sizeof(i64));
|
||||||
printf("Size of u64: %" PRIu64 "\n", sizeof(u64));
|
QINFO("Size of u64: %" PRIu64, sizeof(u64));
|
||||||
printf("Size of f32: %lu\n", sizeof(f32));
|
QINFO("Size of f32: %lu", sizeof(f32));
|
||||||
printf("Size of f64: %lu\n", sizeof(f64));
|
QINFO("Size of f64: %lu", sizeof(f64));
|
||||||
|
|
||||||
QFATAL("Test");
|
QINFO("Creating a List...");
|
||||||
QERROR("Test");
|
List my_list = listCreate();
|
||||||
QWARN("Test");
|
QINFO("Pushing to my_list...")
|
||||||
QINFO("Test");
|
i32 pushVal = 42;
|
||||||
QDEBUG("Test");
|
listPush(&my_list, &pushVal);
|
||||||
|
i32 peekVal = *(i32 *)listPeek(&my_list);
|
||||||
|
|
||||||
printf("\nCreating new zone 4K in size...\n");
|
QDEBUG("Peeking value off of my_list: %" PRId32, peekVal);
|
||||||
Zone *test_zone = zoneCreate(4096);
|
|
||||||
|
|
||||||
void *test_alloc = zoneAlloc(test_zone, 4);
|
QINFO("Pushing another number to my_list...");
|
||||||
void *test_alloc2 = zoneAlloc(test_zone, 4);
|
i32 pushVal2 = 169420;
|
||||||
|
listPush(&my_list, &pushVal2);
|
||||||
|
peekVal = *(i32 *)listPeek(&my_list);
|
||||||
|
|
||||||
printf("Address of test_zone: %p\n", (void *)test_zone);
|
QDEBUG("Peeking value off of my_list: %" PRId32, peekVal);
|
||||||
printf("Address of test_alloc: %p\n", test_alloc);
|
|
||||||
printf("Address of test_alloc2: %p\n\n", test_alloc2);
|
|
||||||
|
|
||||||
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);
|
peekVal = *(i32 *)listPeek(&my_list);
|
||||||
printf("Freeing test_free...\n");
|
|
||||||
|
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user