#include "queue.h"
typedef struct QU_Elem {
Ptr next;
Ptr prev;
} QU_Elem;
typedef struct QU_Head {
Ptr first;
Ptr last;
} QU_Head;
QU_init(QU_Elem *q);
QU_insert(QU_Elem *q1, QU_Elem *q2);
QU_remove(QU_Elem *q);
QU_move(QU_Elem *q1, QU_Elem *q2);
QU_HEAD
QU_ELEMENT
QU_INIT(p)
QU_INSERT(pInsertThisElement, pInFrontOfThisElement)
QU_PREPEND(pInsertThisElement, pAtBeginOfThisQueue)
QU_APPEND(pInsertThisElement, pAtEndOfThisQueue)
QU_REMOVE(p)
QU_MOVE(pMoveMe, pBeforeThisElement)
QU_FIRST(p)
QU_LAST(p)
QU_NEXT(p)
QU_PREV(p)
QU_EQUAL(p1, p2)
QU_ facilities provide a uniform mechanism for manipulation of doubly linked circular lists. A queue is a circular doubly linked list. Queues are often used for implementation of sequences and sets. A queue entry is linked to the next by a pair of pointers. The first pointer (next) is the forward link. It specifies the location of the succeeding entry. The second pointer (prev) is the backward link, it specifies the location of the preceding entry.
A queue is specified by a queue header (QU_Head). Structure of queue header is same as queue element (two pointers). The forward link of the header (first) is called head of the queue. The backward link of the header (last) is called the tail of the queue.
Make no assumptions about the structure of this type. It may change in the future. All manipulation of queue elements must be accomplished solely by the functions in this queue module.
(As an example, if this code is ever moved into a multi-threading environment, some elements may be added to the header, for mutual exclusion while manipulating the queue pointers.)
Do not declare queue pointers in your own structures. Instead, declare the first element of your structures as either QU_ELEMENT or QU_HEAD. No variable name is necessary.
Two basic operations can be performed on queues: insertion of entries and removal of entries.
QU_ facilities are not protected against asynchronous preemption and should not be used when asynchronous preemption can result into inconsistencies. SF_quInsert and SF_quRemove are expected to be atomic (non-preemptable during the entire operation).
QU_init, QU_insert, QU_remove and QU_move all operate on an abstract data type "QU_Elem". Objects that queue management facilities manipulate are expected to be data types that allow for a QU_Elem to be casted over them.
QU_init initializes a QU_Elem so that it can be used in subsequent operations. A QU_Elem is initialized by having its "next" and "prev" field point to itself. An initialized QU_Elem is an empty circular list.
QU_insert(q1, q2) inserts linked list q1 before list q2. The result is a linked list that contains all members of q1 and q2.
It is interesting to note that the order of arguments is not important. The result of QU_insert(q1, q2) and QU_insert(q2, q1) is the same. Figure 6.3 illustrates this.
QU_move moves QU_Elem q1 to end of q2. This is equivalent to the commonly used coding sequence:
QU_remove(q1);
QU_insert(q2, q1);
QU_ also provides the following set of macros to simplify coding.
QU_HEAD QU_ELEMENT
QU_INITIALIZE(q)
QU_INIT(p) QU_INSERT(pInsertThisElement, pInFrontOfThisElement) QU_PREPEND(pInsertThisElement, pAtBeginOfThisQueue) QU_APPEND(pInsertThisElement, pAtEndOfThisQueue) QU_REMOVE(p) QU_MOVE(pMoveMe, pBeforeThisElement)
QU_FIRST(p) QU_LAST(p)
QU_NEXT(p) QU_PREV(p)
QU_EQUAL(p1, p2)
for (pElement = QU_FIRST(pHead);
! QU_EQUAL(pElement, pHead);
pElement = QU_NEXT(pElement))
{
...
}
QU_FREE(pQHead){