blob: 36afaee88cc2c6e8da8e251ebbd15200c40fb36a [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <utils/list.h>
#include <utils/attribute.h>
typedef struct list_node node_t;
int list_init(list_t *l)
{
assert(l != NULL);
l->head = NULL;
return 0;
}
static node_t *make_node(void *data)
{
node_t *n = malloc(sizeof(*n));
if (n != NULL) {
n->data = data;
n->next = NULL;
}
return n;
}
int list_prepend(list_t *l, void *data)
{
node_t *n = make_node(data);
if (n == NULL) {
return -1;
}
return list_prepend_node(l, n);
}
int list_append(list_t *l, void *data)
{
node_t *n = make_node(data);
if (n == NULL) {
return -1;
}
return list_append_node(l, n);
}
bool list_is_empty(list_t *l)
{
assert(l != NULL);
return l->head == NULL;
}
bool list_exists(list_t *l, void *data, int(*cmp)(void *, void *))
{
assert(l != NULL);
for (node_t *n = l->head; n != NULL; n = n->next) {
if (!cmp(n->data, data)) {
return true;
}
}
return false;
}
int list_length(list_t *l)
{
assert(l != NULL);
int i = 0;
for (node_t *n = l->head; n != NULL; n = n->next) {
i++;
}
return i;
}
int list_index(list_t *l, void *data, int(*cmp)(void *, void *))
{
assert(l != NULL);
int i = 0;
for (node_t *n = l->head; n != NULL; n = n->next, i++) {
if (!cmp(n->data, data)) {
return i;
}
}
return -1;
}
int list_foreach(list_t *l, int(*action)(void *, void *), void *token)
{
assert(l != NULL);
for (node_t *n = l->head; n != NULL; n = n->next) {
int res = action(n->data, token);
if (res != 0) {
return res;
}
}
return 0;
}
static int remove(list_t *l, void *data, int (*cmp)(void *, void *),
bool should_free)
{
assert(l != NULL);
for (node_t *prev = NULL, *n = l->head; n != NULL; prev = n, n = n->next) {
if (!cmp(n->data, data)) {
if (prev == NULL) {
/* Removing the list head. */
l->head = n->next;
} else {
prev->next = n->next;
}
if (should_free) {
free(n);
}
return 0;
}
}
return -1;
}
int list_remove(list_t *l, void *data, int(*cmp)(void *, void *))
{
return remove(l, data, cmp, true);
}
int list_remove_all(list_t *l)
{
assert(l != NULL);
for (node_t *n = l->head; n != NULL;) {
node_t *temp = n->next;
free(n);
n = temp;
}
l->head = NULL;
return 0;
}
int list_destroy(UNUSED list_t *l)
{
/* Nothing required. */
return 0;
}
int list_prepend_node(list_t *l, node_t *node)
{
assert(l != NULL);
assert(node != NULL);
node->next = l->head;
l->head = node;
return 0;
}
int list_append_node(list_t *l, node_t *node)
{
assert(l != NULL);
assert(node != NULL);
node->next = NULL;
if (l->head == NULL) {
l->head = node;
} else {
node_t *end;
for (end = l->head; end->next != NULL; end = end->next);
end->next = node;
}
return 0;
}
int list_remove_node(list_t *l, void *data, int(*cmp)(void *, void *))
{
return remove(l, data, cmp, false);
}
int list_remove_all_nodes(list_t *l)
{
assert(l != NULL);
l->head = NULL;
return 0;
}