/* $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