Files
MentOS/mentos/src/klib/list.c
T
Enrico Fraccaroli (Galfurian) 1b2bc49d41 Update license and remove unused files.
2022-01-27 15:12:36 -05:00

331 lines
6.1 KiB
C

/// @file list.c
/// @brief
/// @copyright (c) 2014-2022 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "klib/list.h"
#include "assert.h"
#include "string.h"
#include "mem/slab.h"
static inline listnode_t *__node_alloc()
{
listnode_t *node = kmalloc(sizeof(listnode_t));
memset(node, 0, sizeof(listnode_t));
return node;
}
static inline void __node_dealloc(listnode_t *node)
{
assert(node && "Invalid pointer to node.");
kfree(node);
}
static inline void __list_dealloc(list_t *list)
{
assert(list && "Invalid pointer to list.");
kfree(list);
}
list_t *list_create()
{
list_t *list = kmalloc(sizeof(list_t));
memset(list, 0, sizeof(list_t));
return list;
}
unsigned int list_size(list_t *list)
{
assert(list && "List is null.");
return list->size;
}
int list_empty(list_t *list)
{
assert(list && "List is null.");
if (list->size == 0) {
return 1;
}
return 0;
}
listnode_t *list_insert_front(list_t *list, void *value)
{
assert(list && "List is null.");
assert(value && "Value is null.");
// Create a new node.
listnode_t *node = __node_alloc();
list->head->prev = node;
node->next = list->head;
node->value = value;
// If it's the first element, then it's both head and tail
if (!list->head) {
list->tail = node;
}
list->head = node;
list->size++;
return node;
}
listnode_t *list_insert_back(list_t *list, void *value)
{
assert(list && "List is null.");
assert(value && "Value is null.");
// Create a new node.
listnode_t *node = __node_alloc();
node->prev = list->tail;
if (list->tail != NULL) {
list->tail->next = node;
}
node->value = value;
if (list->head == NULL) {
list->head = node;
}
list->tail = node;
list->size++;
return node;
}
void *list_remove_node(list_t *list, listnode_t *node)
{
assert(list && "List is null.");
assert(node && "Node is null.");
if (list->head == node) {
return list_remove_front(list);
} else if (list->tail == node) {
return list_remove_back(list);
}
void *value = node->value;
node->next->prev = node->prev;
node->prev->next = node->next;
list->size--;
__node_dealloc(node);
return value;
}
void *list_remove_front(list_t *list)
{
assert(list && "List is null.");
if (list->head == NULL) {
return NULL;
}
listnode_t *node = list->head;
void *value = node->value;
list->head = node->next;
if (list->head) {
list->head->prev = NULL;
}
__node_dealloc(node);
list->size--;
return value;
}
void *list_remove_back(list_t *list)
{
assert(list && "List is null.");
if (list->head == NULL) {
return NULL;
}
listnode_t *node = list->tail;
void *value = node->value;
list->tail = node->prev;
if (list->tail) {
list->tail->next = NULL;
}
__node_dealloc(node);
list->size--;
return value;
}
listnode_t *list_find(list_t *list, void *value)
{
listnode_foreach(listnode, list)
{
if (listnode->value == value) {
return listnode;
}
}
return NULL;
}
void list_push_back(list_t *list, void *value)
{
assert(list && "List is null.");
assert(value && "Value is null.");
list_insert_back(list, value);
}
listnode_t *list_pop_back(list_t *list)
{
assert(list && "List is null.");
if (!list->head) {
return NULL;
}
listnode_t *node = list->tail;
list->tail = node->prev;
if (list->tail) {
list->tail->next = NULL;
}
list->size--;
return node;
}
listnode_t *list_pop_front(list_t *list)
{
assert(list && "List is null.");
if (!list->head) {
return NULL;
}
listnode_t *node = list->head;
list->head = list->head->next;
list->size--;
return node;
}
void list_push_front(list_t *list, void *value)
{
assert(list && "List is null.");
assert(value && "Value is null.");
list_insert_front(list, value);
}
void *list_peek_front(list_t *list)
{
assert(list && "List is null.");
if (!list->head) {
return NULL;
}
return list->head->value;
}
void *list_peek_back(list_t *list)
{
assert(list && "List is null.");
if (!list->tail) {
return NULL;
}
return list->tail->value;
}
int list_get_index_of_value(list_t *list, void *value)
{
assert(list && "List is null.");
assert(value && "Value is null.");
int idx = 0;
listnode_foreach(listnode, list)
{
if (listnode->value == value) {
return idx;
}
++idx;
}
return -1;
}
listnode_t *list_get_node_by_index(list_t *list, unsigned int index)
{
assert(list && "List is null.");
if (index >= list_size(list)) {
return NULL;
}
unsigned int curr = 0;
listnode_foreach(listnode, list)
{
if (index == curr) {
return listnode;
}
curr++;
}
return NULL;
}
void *list_remove_by_index(list_t *list, unsigned int index)
{
assert(list && "List is null.");
listnode_t *node = list_get_node_by_index(list, index);
if (node != NULL) {
return list_remove_node(list, node);
}
return NULL;
}
void list_destroy(list_t *list)
{
assert(list && "List is null.");
// Deallocate each node.
listnode_t *node = list->head;
while (node != NULL) {
listnode_t *save = node;
node = node->next;
__node_dealloc(save);
}
// Free the list.
__list_dealloc(list);
}
void list_merge(list_t *target, list_t *source)
{
assert(target && "Target list is null.");
assert(source && "Source list is null.");
// Destructively merges source into target.
if (target->tail) {
target->tail->next = source->head;
} else {
target->head = source->head;
}
if (source->tail) {
target->tail = source->tail;
}
target->size += source->size;
__list_dealloc(source);
}