/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:queue.h 12.0$ */
/* $ACIS:queue.h 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/rvd/h/RCS/queue.h,v $ */

#if !defined(lint) && !defined(LOCORE) && defined(RCS_HDRS)
static char *rcsidqueue = "$Header:queue.h 12.0$";
#endif



/* Copyright 1984 by the Massachusetts Institute of Technology */
/* See permission and disclaimer notice in the file "notice.h" */
#include "notice.h"

/* Data structure declarations and macro definitions for the queue manipulation
 * functions.  The queues are double-ended queues maintained in the VAX
 * standard style: every queueable object has as its first two longwords
 * forward and backward pointers.  When the object is not in a queue both
 * pointers point to the object itself.
 * Queues are assumed to be headed by a queue header, which looks like a
 * queueable object (begins with forward and backward pointers).
 * This package depends on the VAX library "insque" and "remque" functions.
 * Unfortunately, it also depends on an undocumented feature: remque returns
 * its argument.  This should be carefully checked in porting this code.
 */


struct	qelem {				/* a generic queue element */
	struct	qelem	*q_forw;	/* forward link */
	struct	qelem	*q_back;	/* backward link */
};


/* Insert an element at the head of a queue.  First argument is a pointer
 * to the element, second is a pointer to the queue header.
 */

#define	ins_q_head(e, q)	insque((struct qelem *)(e), \
(struct qelem *) (q))


/* Insert an element at the tail of a queue.  First argument is a pointer to
 * the element, second is a pointer to the queue header.
 */

#define	ins_q_tail(e, q)	insque((struct qelem *)(e), \
((struct qelem *)(q))->q_back)


/* Remove the element at the head of a queue and return it cast to a specified
 * type.  First argument is a pointer to the queue header, second is the type
 * of element to be returned.  Returns NULL if the queue is empty.
 */

#define	rem_q_head(q, t)	(q_empty((struct qelem *)(q)) ? NULL : \
(t)remque(((struct qelem *)(q))->q_forw))


/* Remove the element at the tail of a queue and return it cast to a specified
 * type.  First argument is a pointer to the queue header, second is the type
 * of element to be returned.  Returns NULL if the queue is empty.
 */

#define	rem_q_tail(q, t)	(q_empty((struct qelem *)(q)) ? NULL : \
(t)remque(((struct qelem *)(q))->q_back))


/* Return nonzero if the specified queue is empty, 0 otherwise.  The argument
 * is a pointer to the queue header.
 */

#define	q_empty(q)		(((struct qelem *)(q))->q_forw == \
(struct qelem *)(q))


/* Return nonzero if the specified element is presently in a queue, 0
 * otherwise.  Argument is a pointer to the element.
 */

#define	enqueued(e)		(((struct qelem *)(e))->q_forw != \
(struct qelem *)(e))


/* Insert element e after element p in whatever queue p is presently
 * in.  This is just insque, with the appropriate casts done already.
 */

#define	ins_q_after(e, p)	insque((struct qelem *)(e), \
(struct qelem *)(p))


/* Insert element e before element p in whatever queue p is presently
 * in.
 */

#define	ins_q_before(e, p)	insque((struct qelem *)(e), \
((struct qelem *)(p))->q_back)


/* Remove the specified element from whatever queue it's presently in.  This
 * is just remque with the appropriate casts already done.
 */

#define	rem_q_elem(e)		(void)remque((struct qelem *)(e))


/* Return a pointer to the element at the head of the specified queue, cast
 * to a specified type.  First argument is a pointer to the queue header,
 * second is the type of element to be returned.  Returns NULL if the queue
 * is empty.
 */

#define	q_head(q, t)		(q_empty(q) ? NULL : \
(t)((struct qelem *)(q))->q_forw)


/* Return a pointer to the element at the tail of the specified queue, cast
 * to a specified type.  First argument is a pointer to the queue header,
 * second is the type of element to be returned.  Returns NULL if the queue
 * is empty.
 */

#define	q_tail(q, t)		(q_empty(q) ? NULL : \
(t)((struct qelem *)(q))->q_back)


/* Initialize a queue header so its forward and backward links point to itself.
 */

#define	q_init(q)		((struct qelem *)(q))->q_forw = \
((struct qelem *)(q))->q_back = (struct qelem *)(q)

/* Allocate an object and type it.
 */

#define	q_alloc(type,tag)	((type *)obj_alloc(sizeof(type), tag))
