nativeos/kernel/stdkern/list.c

244 lines
3.9 KiB
C

/*
* This file is part of NativeOS
* Copyright (C) 2015-2021 The NativeOS contributors
* SPDX-License-Identifier: GPL-3.0-only
*/
#include <sys/list.h>
#include <sys/stdkern.h>
static inline void
chain(listnode_t *car, listnode_t *cdr)
{
if (car)
car->next = cdr;
if (cdr)
cdr->prev = car;
}
static listnode_t *
listnode_alloc(void *ptr)
{
listnode_t *node = (listnode_t *) malloc(sizeof(listnode_t));
if (node) {
node->prev = NULL;
node->next = NULL;
node->data = ptr;
}
return node;
}
static void *
listnode_free(listnode_t *node)
{
void *ptr = node->data;
node->prev = NULL;
node->next = NULL;
node->data = NULL;
free(node);
return ptr;
}
list_t *
list_alloc()
{
list_t *list = (list_t *) malloc(sizeof(list_t));
if (list) {
list->count = 0;
list->head = NULL;
list->tail = NULL;
}
return list;
}
unsigned int
list_count(list_t *list)
{
return list->count;
}
listnode_t *
list_append(list_t *list, void *ptr)
{
listnode_t *node = listnode_alloc(ptr);
if (node) {
chain(list->tail, node);
list->tail = node;
if (!list->head)
list->head = node;
list->count++;
}
return node;
}
listnode_t *
list_prepend(list_t *list, void *ptr)
{
listnode_t *node = listnode_alloc(ptr);
if (node) {
chain(node, list->head);
list->head = node;
if (!list->tail)
list->tail = node;
list->count++;
}
return node;
}
listnode_t *
list_insert(list_t *list, void *ptr, unsigned int before)
{
listnode_t *cur = list->head, *newnode, *prevnode;
/*
* Shortcircuit head and tail of the list. I dislike having multiple
* algorithms in the same function, but it is useful to filter out
* all the "prev is null", "next is null", "assign node to head" and
* "assign node to tail" stuff.
*/
if (!before) /* head */
return list_prepend(list, ptr);
if (before >= list->count) /* tail */
return list_append(list, ptr);
/* Inserts the new node before cur. */
while (before--)
cur = cur->next;
newnode = listnode_alloc(ptr);
if (newnode) {
prevnode = cur->prev;
chain(prevnode, newnode);
chain(newnode, cur);
list->count++;
}
return newnode;
}
void *
list_first(list_t *list)
{
if (list->head)
return list->head->data;
else
return NULL;
}
void *
list_last(list_t *list)
{
if (list->tail)
return list->tail->data;
else
return NULL;
}
void *
list_at(list_t *list, unsigned int idx)
{
listnode_t *cur = list->head;
if (idx >= list->count)
return NULL;
while (idx--) {
cur = cur->next;
}
return cur->data;
}
unsigned int
list_index(list_t *list, void *ptr)
{
listnode_t *cur = list->head;
unsigned int i = 0;
while (cur) {
if (cur->data == ptr)
return i;
cur = cur->next;
i++;
}
return (unsigned int) -1;
}
void
list_empty(list_t *list)
{
listnode_t *cur = list->head;
if (list->count) {
while (cur) {
listnode_free(cur);
cur = cur->next;
}
list->head = NULL;
list->tail = NULL;
list->count = 0;
}
}
static void *
list_unchain(list_t *list, listnode_t *node)
{
listnode_t *prev = node->prev, *next = node->next;
if (prev)
prev->next = next;
else
list->head = node->next;
if (next)
next->prev = prev;
else
list->tail = node->prev;
list->count--;
return listnode_free(node);
}
void *
list_remove(list_t *list, unsigned int at)
{
listnode_t *cur = list->head;
if (!list->head || at >= list->count)
return NULL;
while (at--) {
cur = cur->next;
if (!cur) {
return NULL;
}
}
return list_unchain(list, cur);
}
void *
list_delete(list_t *list, void *ptr)
{
listnode_t *cur = list->head;
while (cur) {
if (cur->data == ptr) {
return list_unchain(list, cur);
}
cur = cur->next;
}
return NULL;
}
void *
list_pop_head(list_t *list)
{
if (list->head)
return list_unchain(list, list->head);
else
return NULL;
}
void *
list_pop_tail(list_t *list)
{
if (list->tail)
return list_unchain(list, list->tail);
else
return NULL;
}
void
list_free(list_t *list)
{
list_empty(list);
free(list);
}