/*
    Copyright 2001 (c) by Claudio Jeker,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public 
    Licence. A full copy of the GNU GPL is provided in the file COPYING 
    found in the development root of Topsy.
*/
/*
	
    File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/Topsy/Attic/doubleq.h,v $
    Affiliation:           ETH Zuerich, TIK
    Version:               $Revision: 2922 $
    Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $  by: $Author: baderma $
 
*/

/* doubleq.h: a doubly linked list with no souperfluous stuff
	 
	 Idea comes from OpenBSDs queue(3) and /usr/src/sys/sys/queue.h
 
	 Following MACROS are defined:
 
	 DOUBLEQ_ENTRY(TYPE);
	 * add next, prev pointers for an element (struct TYPE *dq_next, *dq_prev)
	 
	 DOUBLEQ_INIT(ELM, FIELD);
	 * init the element (sets pointer to NULL
	 
	 DOUBLEQ_ADDAFTER(LIST_ELM, ELM, FIELD);
	 * add element after LIST_ELM
	 
	 DOUBLEQ_ADDBEFOR(LIST_ELM, ELM, FIELD);
	 * add element in front of LIST_ELM
	 
	 DOUBLEQ_REMOVE(ELM, FIELD);
	 * remove element from list
	 
	 DOUBLEQ_REPLACE(LIST_ELM, ELM, FIELD);
	 * replace LIST_ELM with ELM
	 
	 DOUBLEQ_NEXT(ELM, FIELD);
	 * return next element
	 
	 DOUBLEQ_PREV(ELM, FIELD);
	 * return previous element
 
	 DOUBLEQ_LAST(ELM, FIELD);
	 * return true if last element
	 
	 DOUBLEQ_FIRST(ELM, FIELD);
	 * return true if first element
	 
	 DOUBLEQ_FOREACH(ELM, VAR, FIELD)
	 * cycle through the list starting at ELM to the end
	 
	 DOUBLEQ_HCAEROF(ELM, VAR, FIELD)
	 * the same but this time reverse direction
 
 */

#define DOUBLEQ_ENTRY(type)																								\
		struct {																															\
			struct type *dq_next;																								\
			struct type *dq_prev;																								\
		}

#define DOUBLEQ_INIT(elm, field)																					\
		do {																																	\
			(elm)->field.dq_prev = NULL;																				\
			(elm)->field.dq_next = NULL;																				\
		} while (0)

#define DOUBLEQ_ADDAFTER(listelm, elm, field)															\
		do {																																	\
			(elm)->field.dq_prev = (listelm);																		\
			if (( (elm)->field.dq_next = (listelm)->field.dq_next ) != NULL )		\
				(elm)->field.dq_next->field.dq_prev = (elm);											\
			(listelm)->field.dq_next = (elm);																		\
		} while (0)

#define DOUBLEQ_ADDBEFORE(listelm, elm, field)														\
		do {																																	\
			(elm)->field.dq_next = (listelm);																		\
			if (( (elm)->field.dq_prev = (listelm)->field.dq_prev ) != NULL )		\
				(elm)->field.dq_prev->field.dq_next = (elm);											\
			(listelm)->field.dq_prev = (elm);																		\
		} while (0)

#define DOUBLEQ_REMOVE(elm, field)																				\
		do {																																	\
			if ( (elm)->field.dq_next != NULL )																	\
				(elm)->field.dq_next->field.dq_prev = (elm)->field.dq_prev;				\
			if ( (elm)->field.dq_prev != NULL )																	\
				(elm)->field.dq_prev->field.dq_next = (elm)->field.dq_next;				\
		} while (0)

#define DOUBLEQ_REPLACE(listelm, elm, field)															\
		do {																																	\
			(elm)->dq_next = (listelm)->dq_next;																\
			(elm)->dq_prev = (listelm)->dq_prev;																\
		} while (0)

#define DOUBLEQ_NEXT(elm, field)																					\
		((elm)->field.dq_next)

#define DOUBLEQ_PREV(elm, field)																					\
		((elm)->field.dq_prev)

#define DOUBLEQ_LAST(elm, field)																					\
		((elm)->field.dq_next == NULL)

#define DOUBLEQ_FIRST(elm, field)																					\
		((elm)->field.dq_prev == NULL)

#define DOUBLEQ_FOREACH(elm, var, field)																	\
		for ((var) = (elm);																										\
				 (var) != NULL;																										\
				 (var) = DOUBLEQ_NEXT(var, field))

#define DOUBLEQ_HCAEROF(elm, var, field)																	\
		for ((var) = (elm);																										\
				 (var) != NULL;																										\
				 (var) = DOUBLEQ_PREV(var, field))
