quakeforge/libs/util/llist.c

266 lines
4.9 KiB
C

/*
llist.c
Linked list functions
Copyright (C) 2003 Brian Koropoff
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "QF/llist.h"
static llist_node_t *
llist_newnode (llist_t *list, void *data)
{
llist_node_t *node = calloc (1, sizeof (llist_node_t));
node->parent = list;
node->data = data;
return node;
}
VISIBLE llist_t *
llist_new (void (*freedata)(void *element, void *userdata), qboolean (*cmpdata)(const void *element, const void *comparison, void *userdata), void *userdata)
{
llist_t *new = calloc (1, sizeof (llist_t));
new->freedata = freedata;
new->cmpdata = cmpdata;
new->userdata = userdata;
return new;
}
VISIBLE void
llist_flush (llist_t *list)
{
llist_node_t *node, *next;
if (!list)
return;
for (node = list->start; node; node = next) {
next = node->next;
list->freedata (node->data, list->userdata);
free (node);
}
list->start = list->end = 0;
}
VISIBLE void
llist_delete (llist_t *list)
{
if (!list)
return;
llist_flush (list);
free (list);
}
VISIBLE llist_node_t *
llist_append (llist_t *list, void *element)
{
llist_node_t *node = llist_newnode (list, element);
if (!list)
return 0;
if (list->end) {
list->end->next = node;
node->prev = list->end;
list->end = node;
} else
list->start = list->end = node;
return node;
}
VISIBLE llist_node_t *
llist_prefix (llist_t *list, void *element)
{
llist_node_t *node = llist_newnode (list, element);
if (!list)
return 0;
if (list->start) {
list->start->prev = node;
node->next = list->start;
list->start = node;
} else
list->start = list->end = node;
return node;
}
VISIBLE llist_node_t *
llist_getnode (llist_t *list, void *element)
{
llist_node_t *node;
if (!list)
return 0;
for (node = list->start; node; node = node->next)
if (node->data == element)
return node;
return 0;
}
VISIBLE llist_node_t *
llist_insertafter (llist_node_t *ref, void *element)
{
llist_node_t *node = llist_newnode (ref->parent, element);
if (!ref)
return 0;
if (ref->next)
ref->next->prev = node;
else
ref->parent->end = node;
node->prev = ref;
node->next = ref->next;
ref->next = node;
return node;
}
VISIBLE llist_node_t *
llist_insertbefore (llist_node_t *ref, void *element)
{
llist_node_t *node = llist_newnode (ref->parent, element);
if (!ref)
return 0;
if (ref->prev)
ref->prev->next = node;
else
ref->parent->start = node;
node->next = ref;
node->prev = ref->prev;
ref->prev = node;
return node;
}
VISIBLE void *
llist_remove (llist_node_t *ref)
{
void *element;
if (!ref)
return 0;
if (ref == ref->parent->iter)
ref->parent->iter = ref->next;
if (ref->prev)
ref->prev->next = ref->next;
else
ref->parent->start = ref->next;
if (ref->next)
ref->next->prev = ref->prev;
else
ref->parent->end = ref->prev;
element = ref->data;
free (ref);
return element;
}
VISIBLE unsigned int
llist_size (llist_t *llist)
{
unsigned int i;
llist_node_t *n;
if (!llist->start)
return 0;
else for (i = 0, n = llist->start; n; n = n->next, i++);
return i;
}
VISIBLE void
llist_iterate (llist_t *list, llist_iterator_t iterate)
{
llist_node_t *node;
if (!list || !list->start)
return;
for (node = list->start; node; node = list->iter) {
list->iter = node->next;
if (!iterate (node->data, node))
break;
}
list->iter = 0;
}
VISIBLE void *
llist_find (llist_t *list, void *comparison)
{
llist_node_t *node;
if (!list)
return 0;
for (node = list->start; node; node = node->next)
if (list->cmpdata (node->data, comparison, list->userdata))
return node->data;
return 0;
}
VISIBLE llist_node_t *
llist_findnode (llist_t *list, void *comparison)
{
llist_node_t *node;
if (!list || !list->cmpdata)
return 0;
for (node = list->start; node; node = node->next)
if (list->cmpdata (node->data, comparison, list->userdata))
return node;
return 0;
}
VISIBLE void *
llist_createarray (llist_t *list, size_t esize)
{
void *ptr, *array = malloc (llist_size (list) * esize);
llist_node_t *node;
for (ptr = array, node = list->start; node; node = node->next, ptr = (char*)ptr + esize)
memcpy (ptr, node->data, esize);
return array;
}