/* $Id: lists.c,v 1.8 2003/02/26 10:55:45 aa5779 Exp $ */
/* lists.c -- routines for processing generic lists */
/*
Copyright (C) 2001, 2002 Artem V. Andreev (artem@AA5779.spb.edu)
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 the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include "util.h"
#include "lists.h"
/*** \file
This file contains routines for generic list maninpulation.
\include[lists.h]
*/
/*** \group[Functions] */
/*** \function
Destroys a single item of a list
\arg[item] the pointer to a given item
\arg[destroy] user-supplied destruction function, may be NULL
\arg[size] actual size of an item
*/
void list_free(list_t item, list_destroy_t destroy, int size)
{
if(destroy)
destroy(item);
if(size)
free_chunk(item, size);
}
/*** \function
Prepends an item \var[base] to a list \var[new]
\note both may be NULLs
\returns a new list
*/
list_t list_add(list_t base, list_t new)
{
if(!new)
return base;
((baselist_t *)new)->next = base;
return new;
}
/*** \function
Finds the first item in a list matching \var[key] according to \var[predicate]
\returns the item found, or NULL if none
*/
list_t list_find(list_t base, void *key, list_predicate_t predicate)
{
baselist_t *iter = base;
if(!predicate)
fatal_error("predicate == NULL in list_find");
for(; iter; iter = iter->next)
{
if(predicate(iter, key))
return iter;
}
return NULL;
}
/**** \function
\returns the length of a list
*/
int list_length(list_t l)
{
baselist_t *iter = l;
int len;
for(len = 0; iter; iter = iter->next, len++)
;
return len;
}
/*** \function
\returns \var[n]th item of a list (starting with 0),
NULL if the list contains less than \code[n + 1] items
*/
list_t list_nth(list_t l, int n)
{
baselist_t *iter = l;
for(; iter; iter = iter->next, n--)
{
if(!n)
return iter;
}
return NULL;
}
/**** \function
Executes \var[iterator] for each item in \var[base]
*/
void list_foreach(list_t base, list_iterator_t iterator, void *extra)
{
baselist_t *iter = base;
for(; iter; iter = iter->next)
iterator(iter, extra);
}
/**** \function
Inserts a \var[new] item into \var[base] list after an item matching \var[after].
If no such item is found, no insertion is performed.
If \var[after] is NULL, the function is equivalent to \see[functions][list_add]
\returns a new list
*/
list_t list_insert(list_t base, void *after, list_t new, list_predicate_t predicate)
{
baselist_t *item;
if(!after)
return list_add(base, new);
item = list_find(base, after, predicate);
if(item)
{
((baselist_t *)new)->next = item->next;
item->next = new;
}
return base;
}
/**** \function
Appends a \var[new] item to the list
\returns \var[base]
*/
list_t list_append(list_t base, list_t new)
{
baselist_t *item;
if(!base)
return new;
for(item = base; item->next; item = item->next)
;
item->next = new;
return base;
}
/**** \function
Discards the head of the list, calling \see[functions][list_free] on it
\returns the tail of the list
*/
list_t list_pop(list_t base, list_destroy_t destroy, int elsize)
{
list_t next;
if(!base)
return NULL;
next = ((baselist_t *)base)->next;
list_free(base, destroy, elsize);
return next;
}
/**** \function
Removes the first item matching \var[key], calling \see[functions][list_free] on it.
If no such item is found, nothing happens
\returns a new list
*/
list_t list_remove(list_t base, void *key, list_predicate_t predicate, list_destroy_t destroy, int elsize)
{
baselist_t *item, *prev = NULL;
for(item = base; item; prev = item, item = item->next)
{
if(predicate(item, key))
{
if(prev)
prev->next = item->next;
else base = item->next;
list_free(item, destroy, elsize);
break;
}
}
return base;
}
/*** \function
Like the previous, but removes all the items matching \var[key]
*/
list_t list_remove_all(list_t base, void *key, list_predicate_t predicate, list_destroy_t destroy, int elsize)
{
baselist_t *item, *prev = NULL, *temp;
for(item = base; item; item = temp)
{
temp = item->next;
if(!predicate(item, key))
prev = item;
else
{
if(prev)
prev->next = temp;
else base = temp;
list_free(item, destroy, elsize);
}
}
return base;
}
/*** \function
Destroys all the items of the list, calling \see[functions][list_free] on them.
*/
void list_delete(list_t base, list_destroy_t destroy, int elsize)
{
baselist_t *iter, *temp;
for(iter = base; iter; iter = temp)
{
temp = iter->next;
list_free(iter, destroy, elsize);
}
}
/*** \function
Reverses the order of items in a list without producing a new list
*/
list_t list_reversip(list_t src)
{
baselist_t *iter, *prev = NULL, *temp;
for(iter = src; iter; iter = temp)
{
temp = iter->next;
iter->next = prev;
prev = iter;
}
return prev;
}
syntax highlighted by Code2HTML, v. 0.9.1