aos/lib/collections/list.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

378 lines
8.5 KiB
C

/**
* \file
* \brief Barrelfish collections library list data structure
*/
/*
* Copyright (c) 2010, 2012, ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich,
* Attn: Systems Group.
*/
#include <collections/list.h>
/******************************************************
* a simple linked list implementation.
******************************************************/
/*
* private functions.
*/
static void list_push(collections_listnode *existing,
collections_listnode *insert)
{
insert->next = existing->next;
insert->prev = existing;
existing->next = insert;
insert->next->prev = insert;
}
static void *list_pop(collections_listnode *n)
{
void *data = n->data;
n->next->prev = n->prev;
n->prev->next = n->next;
n->next = n->prev = NULL;
return data;
}
/*
* Insert the data at the head.
*/
static collections_listnode *list_create_node(collections_listnode *start,
collections_listnode *where,
void *data)
{
collections_listnode *newnode = (collections_listnode *)
malloc(sizeof(collections_listnode));
newnode->data = data;
list_push(where, newnode);
((collections_header_data *)(start->data))->size ++;
return newnode;
}
static void list_destroy_node(collections_listnode *start,
collections_listnode *node)
{
list_pop(node);
free(node);
((collections_header_data*)start->data)->size--;
}
/*
* public functions.
*/
/*
* Creates a new linked list.
*/
void collections_list_create(collections_listnode **start,
collections_release_data func)
{
collections_listnode *t;
//
// this is an empty list containing only the header.
//
t = (collections_listnode *)malloc(sizeof(collections_listnode));
t->next = t->prev = t;
collections_header_data *h = (collections_header_data *)
malloc(sizeof(collections_header_data));
h->size = 0;
h->data_free = func;
h->cur_item = NULL;
t->data = (void *)h;
*start = t;
}
/*
* Releases all the nodes in the list.
*/
void collections_list_release(collections_listnode *start)
{
collections_release_data data_free =
((collections_header_data*)start->data)->data_free;
collections_listnode *cur = start->next;
//
// travel through the rest of the
// list and release all the nodes.
//
while (cur != start)
{
void *data = cur->data;
if (data != NULL && data_free)
{
data_free(data);
}
list_destroy_node(start, cur);
cur = start->next;
}
//
// release the header.
//
free(start->data);
free(start);
return;
}
/*
* Inserts an element in the head of the list.
*/
int32_t collections_list_insert(collections_listnode *start, void *data)
{
collections_listnode *ret = list_create_node(start, start, data);
if (ret) {
// success ...
return 0;
}
return 1;
}
/*
* Inserts an element at the tail of the list.
*/
int32_t collections_list_insert_tail(collections_listnode *start, void *data)
{
collections_listnode *ret = list_create_node(start, start->prev, data);
if (ret) {
// success ...
return 0;
}
return 1;
}
/*
* Returns the data that matches the user provided key.
*/
void *collections_list_find_if(collections_listnode *start,
collections_list_predicate p, void *arg)
{
collections_listnode *cur = start->next;
while (cur != start)
{
if (p(cur->data, arg))
{
return cur->data;
}
cur = cur->next;
}
return NULL;
}
/**
* Remove the first item that matches the given predicate and return it.
*
* \return The removed item.
*/
void *collections_list_remove_if(collections_listnode *start,
collections_list_predicate p, void *arg)
{
collections_listnode *cur = start->next;
while (cur != start)
{
if (p(cur->data, arg))
{
void *data = cur->data;
list_destroy_node(start, cur);
return data;
}
cur = cur->next;
}
return NULL;
}
/**
* Remove all the items that match the given predicate.
*
* \return The number of items removed.
*/
uint32_t collections_list_remove_if_all(collections_listnode *start,
collections_list_predicate p, void *arg)
{
uint32_t items_removed = 0;
collections_listnode *cur = start->next;
while (cur != start)
{
if (p(cur->data, arg))
{
list_destroy_node(start, cur);
items_removed++;
}
cur = cur->next;
}
return items_removed;
}
void *collections_list_remove_ith_item(collections_listnode *start,
uint32_t item)
{
void *element;
uint32_t n = collections_list_size(start);
if (item >= n) {
element = NULL;
} else if (item <= n/2) {
collections_listnode *cur = start->next;
while (item != 0) {
cur = cur->next;
item--;
}
element = cur->data;
list_destroy_node(start, cur);
} else {
collections_listnode *cur = start;
do {
cur = cur ->prev;
item++;
} while (item !=n);
element = cur->data;
list_destroy_node(start, cur);
}
return element;
}
void *collections_list_get_ith_item(collections_listnode *start, uint32_t item)
{
uint32_t n = collections_list_size(start);
if (item >= n) {
return NULL;
}
else if (item <= n / 2)
{
collections_listnode* cur = start->next;
while (item != 0)
{
cur = cur->next;
item--;
}
return cur->data;
}
else
{
collections_listnode *cur = start;
do {
cur = cur->prev;
item++;
} while (item != n);
return cur->data;
}
}
/*
* Return the total number of nodes in the list.
*/
uint32_t collections_list_size(collections_listnode *start)
{
return ((collections_header_data *)(start->data))->size;
}
#if 0
static void* list_front(collections_listnode* start)
{
return (start->next == start) ? NULL : start->next->data;
}
static void* list_back(collections_listnode* start)
{
return (start->prev == start) ? NULL : start->prev->data;
}
#endif
/*
* A set of routines for iteratively traversing through
* the linked list.
*/
/*
* Opens the list for traversal.
*/
int32_t collections_list_traverse_start(collections_listnode *start)
{
collections_header_data* head = (collections_header_data *) start->data;
if (head->cur_item) {
// if the next item is not null, a
// traversal is already in progress.
printf("Error: list is already opened for traversal.\n");
return -1;
}
head->cur_item = start;
return 1;
}
/*
* Fetches the next item in the list.
* If all the items have been fetched,
* returns null.
*/
void *collections_list_traverse_next(collections_listnode *start)
{
collections_header_data *head = (collections_header_data *) start->data;
if (!head->cur_item) {
// asking for the next item without
// starting the traversal.
printf("Error: list must be opened for traversal.\n");
return NULL;
}
head->cur_item = head->cur_item->next;
if (head->cur_item == start)
{
return NULL;
}
else
{
return head->cur_item->data;
}
}
/*
* Finishes the list traversal.
*/
int32_t collections_list_traverse_end(collections_listnode *start)
{
collections_header_data *head = (collections_header_data *) start->data;
if (!head->cur_item) {
// closing without
// starting the traversal.
printf("Error: list must be opened before ending.\n");
return -1;
}
head->cur_item = NULL;
return 1;
}
int collections_list_visit(collections_listnode *start,
collections_list_visitor_func func, void *arg)
{
collections_listnode *cur = start->next;
while (cur != start && func(cur->data, arg))
{
cur = cur->next;
}
return cur == start;
}