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

/* tailq.h: a doubly linked list with head and tail pointer based on macros
 
	 Idea comes from OpenBSDs queue(3) and /usr/src/sys/sys/queue.h
 
	 Following MACROS are defined:
 
	 TAILQ_HEAD(NAME, TYPE);
	 * create a new tailq with name NAME and pointers to structs of type TYPE
	 
	 TAILQ_ENTRY(TYPE);
	 * add next, prev pointers for an element (struct TYPE *tq_next, **tq_prev)
	 
	 TAILQ_INIT(HEAD);
	 * initialize the list
	 
	 TAILQ_ADDHEAD(LIST, ELM, FIELD);
	 * add element in front of the tail queue
 
	 TAILQ_ADDTAIL(LIST, ELM, FIELD);
	 * add element at the end of the tail queue
	 
	 TAILQ_ADDAFTER(LIST, LIST_ELM, ELM, FIELD);
	 * add element after LIST_ELM
	 
	 TAILQ_ADDBEFOR(LIST, LIST_ELM, ELM, FIELD);
	 * add element in front of LIST_ELM
	 
	 TAILQ_EMPTY(LIST);
	 * true if empty
	 
	 TAILQ_REMOVE(LIST, ELM, FIELD);
	 * remove element from list
	 
	 TAILQ_FIRST(LIST);
	 * return first elmenet
	 
	 TAILQ_NEXT(ELM, FIELD);
	 * return next elmenet
	 
	 TAILQ_PREV(ELM, NAME, FIELD);
	 * return previous element
	 
	 TAILQ_LAST(LIST, NAME);
	 * return last element
 
	 TAILQ_FOREACH(LIST, ELM, FIELD)
	 * cycle through the tailq
	
	 TAILQ_HCAEROF(LIST, ELM, FIELD, NAME)
	 * the same but this time reverse direction
 
 */

#define TAILQ_HEAD(name, type)																						\
		struct name {																													\
			struct type *tq_first;																							\
			struct type **tq_last;																							\
		}

#define TAILQ_ENTRY(type)																									\
		struct {																															\
			struct type *tq_next;																								\
			struct type **tq_prev;																							\
		}

#define TAILQ_INIT(headptr)																								\
		do {																																	\
			(headptr)->tq_first = NULL;																					\
			(headptr)->tq_last = &(headptr)->tq_first;													\
		} while (0)

#define TAILQ_ADDHEAD(headptr, elm, field)																\
		do {																																	\
			if (( (elm)->field.tq_next = (headptr)->tq_first ) != NULL ) 				\
				(headptr)->tq_first->field.tq_prev = &(elm)->field.tq_next;				\
			else																																\
				(headptr)->tq_last = &(elm)->field.tq_next;												\
			(elm)->field.tq_prev = &(headptr)->tq_first;												\
			(headptr)->tq_first = (elm);																				\
		} while (0)

#define TAILQ_ADDTAIL(headptr, elm, field)																\
		do {																																	\
			(elm)->field.tq_next = NULL;																				\
			(elm)->field.tq_prev = (headptr)->tq_last;													\
			*(headptr)->tq_last = (elm);																				\
			(headptr)->tq_last = &(elm)->field.tq_next;													\
		} while (0)

#define TAILQ_ADDAFTER(headptr, listelm, elm, field)											\
		do {																																	\
			if (( (elm)->field.tq_next = (listelm)->field.tq_next ) != NULL )		\
				(elm)->field.tq_next->field.tq_prev = &(elm)->field.tq_next;			\
			else																																\
				(headrptr)->tq_last = &(elm)->field.tq_next;											\
			(listelm)->field.tq_next = (elm);																		\
			(elm)->field.tq_prev = &(listelm)->field.tq_next;										\
		} while (0)

#define TAILQ_ADDBEFORE(headptr, listelm, elm, field)											\
		do {																																	\
			(elm)->field.tq_next = (listelm);																		\
			(elm)->field.tq_prev = (listelm)->field.tq_prev;										\
			*(elm)->field.tq_prev = (elm);																			\
			(listelm)->field.tq_prev = &(elm)->field.tq_next;										\
		} while (0)

#define TAILQ_EMPTY(headptr)																							\
		(TAILQ_FIRST(headptr) == NULL)

#define TAILQ_REMOVE(headptr, elm, field)																	\
		do {																																	\
			if (( *(elm)->field.tq_prev = (elm)->field.tq_next ) != NULL )			\
				(elm)->field.tq_next->field.tq_prev = (elm)->field.tq_prev;				\
			else																																\
				(headptr)->tq_last = (elm)->field.tq_prev;												\
		} while (0)

#define TAILQ_FIRST(headptr)																							\
		((headptr)->tq_first)

#define TAILQ_NEXT(elm, field)																						\
		((elm)->field.tq_next)

#define TAILQ_PREV(elm, headfield, field)																	\
		(*((struct headfield*)((elm)->field.tq_prev)->tq_last))

#define TAILQ_LAST(headptr, headfield)																		\
		(*(((struct headfield*)((headptr)->tq_last))->tq_last))

#define TAILQ_FOREACH(headptr, var, field)																\
		for ((var) = TAILQ_FIRST(headptr);																		\
				 (var) != NULL;																										\
				 (var) = TAILQ_NEXT(var, field) )

#define TAILQ_HCAEROF(headptr, var, field, headfield)											\
		for ((var) = TAILQ_LAST(headptr, headfield);													\
				 (var) != NULL;																										\
				 (var) = TAILQ_PREV(var, field, headfield))
