OpenAFS
OpenAFS distributed network file system
/cygdrive/c/src/openafs/openafs.git/repo/src/rx/rx_queue.h
00001 /*
00002  * Copyright 2000, International Business Machines Corporation and others.
00003  * All Rights Reserved.
00004  *
00005  * This software has been released under the terms of the IBM Public
00006  * License.  For details, see the LICENSE file in the top-level source
00007  * directory or online at http://www.openafs.org/dl/license10.html
00008  */
00009 
00010 /* queue.h:  Simple double linked queue package */
00011 
00012 /* It's simple, but, I think, it's pretty nice to use, and it's *very* efficient (especially so with a good optimizing compiler).   WARNING:  Since these functions are implemented as macros, it is best to use only *VERY* simple expressions for all parameters.  Double warning:  this uses a lot of type coercion, so you have to be *REAL* careful.  But C doesn't give me a reasonable alternative (i.e.. in-line expanded functions). */
00013 
00014 #ifndef _RX_QUEUE_
00015 #define _RX_QUEUE_
00016 
00017 /* A queue head is simply a queue element linked to itself (i.e. the null queue is a queue with exactly one element).  Queue elements can be prepended to any structure:  these macros assume that the structure passed is coercible to a (struct q).  Since all of these operations are implemented as macros, the user should beware of side-effects in macro parameters.  Also beware that implicit casting of queue types occurs, so be careful to supply the right parameters at the right times! */
00018 #undef queue                    /* Since some OS (ultrix, etc) have their own */
00019 struct rx_queue {
00020     struct rx_queue *prev;
00021     struct rx_queue *next;
00022 };
00023 
00024 /* Sample usages:
00025 
00026 (*A queue head:*)
00027 struct rx_queue myqueue;
00028 
00029 (*An element for my queue type:*)
00030 struct myelement {
00031     struct rx_queue queue_header;
00032     int mydata;
00033 };
00034 
00035 (*Initialize the queue:*)
00036 queue_Init(&myqueue);
00037 
00038 (*Append a bunch of items to the queue:*)
00039 for (i=0; i<20; i++) {
00040     struct myelement *item = (struct myelement *) malloc(sizeof *item);
00041     item->mydata = i;
00042     queue_Append(&myqueue, item);
00043 }
00044 
00045 (*Scan a queue, incrementing the mydata field in each element, and removing any entries for which mydata>MAX.  Nqe is used by the scan to hold the next queue element, so the current queue element may be removed safely. *)
00046 struct myelement *qe, *nqe;
00047 for (queue_Scan(&myqueue, qe, nqe, myelement)) {
00048     if (++qe->mydata > MAX)  queue_Remove(qe);
00049 }
00050 
00051 (* Count the number of elements in myqueue.  The queue_Scan macro specifies all three elements of the for loop, but an additional initializer and an additional incrementor can be added *)
00052 struct myelement *qe, *nqe;
00053 int n;
00054 for (n=0, queue_Scan(&myqueue, qe, nqe, myelement), n++) {}
00055 
00056 */
00057 
00058 /* INTERNAL macros */
00059 
00060 /* This one coerces the user's structure to a queue element (or queue head) */
00061 #define _RXQ(x) ((struct rx_queue *)(x))
00062 
00063 /* This one adds a queue element (i) before or after another queue element (or queue head) (q), doubly linking everything together.  It's called by the user usable macros, below.  If (a,b) is (next,prev) then the element i is linked after q; if it is (prev,next) then it is linked before q */
00064 /* N.B.  I don't think it is possible to write this expression, correctly, with less than one comma (you can easily write an alternative expression with no commas that works with most or all compilers, but it's not clear that it really is un-ambiguous, legal C-code). */
00065 #define _RXQA(q,i,a,b) (((i->a=q->a)->b=i)->b=q, q->a=i)
00066 
00067 /* These ones splice two queues together.  If (a,b) is (next,prev) then (*q2) is prepended to (*q1), otherwise (*q2) is appended to (*q1). */
00068 #define _RXQS(q1,q2,a,b) \
00069         do { \
00070             if (!queue_IsEmpty(q2)) { \
00071                 ((q2->a->b=q1)->a->b=q2->b)->a=q1->a; \
00072                 q1->a=q2->a; \
00073                 queue_Init(q2); \
00074             } \
00075         } while (0)
00076 
00077 /* This one removes part of queue (*q1) and attaches it to queue (*q2).
00078  * If (a,b) is (next,prev) then the subchain is prepended to (*q2),
00079  * otherwise the subchain is appended to (*q2).
00080  * If (c,d) is (prev,next) then the subchain is the elements in (*q1) before (i),
00081  * otherwise the subchain is the elements in (*q1) after (i).
00082  * If (x,y) is (q1,i) then operation is either BeforePrepend of AfterAppend.
00083  * If (x,y) is (i,q1) then operation is either BeforeAppend or AfterPrepend. */
00084 #define _RXQSP(q1,q2,i,a,b,c,d,x,y) \
00085         do { \
00086             if (!queue_IsEnd(q1, i->c)) { \
00087                 (y->b->a=q2->a)->b=y->b; \
00088                 (x->a->b=q2)->a=x->a; \
00089                 (i->c=q1)->d=i; \
00090             } \
00091         } while (0)
00092 
00093 /* This one moves a chain of elements from (s) to (e) from its
00094  * current position to either before or after element (i)
00095  * if (a,b,x,y) is (prev,next,s,e) then chain is moved before (i)
00096  * if (a,b,x,y) is (next,prev,e,s) then chain is moved after (i) */
00097 #define _RXQMV(i, s, e, a, b, x, y) \
00098         do { \
00099             if (i->a != y) { \
00100                 (e->next->prev=s->prev)->next=e->next; \
00101                 (i->a->b=x)->a=i->a; \
00102                 (y->b=i)->a=y; \
00103             } \
00104         } while (0)
00105 
00106 /* Basic remove operation.  Doesn't update the queue item to indicate it's been removed */
00107 #define _RXQR(i) \
00108         do { \
00109             struct rx_queue *_qp = _RXQ(i); \
00110             (_qp->prev->next = _qp->next)->prev = _qp->prev; \
00111         } while (0)
00112 
00113 /* EXPORTED macros */
00114 
00115 /* Initialize a queue head (*q).  A queue head is just a queue element */
00116 #define queue_Init(q) \
00117         do { _RXQ(q)->prev = _RXQ(q)->next = _RXQ(q); } while (0)
00118 
00119 /* initialize a node in the queue */
00120 #define queue_NodeInit(q) \
00121         do { _RXQ(q)->prev = _RXQ(q)->next = NULL; } while (0)
00122 
00123 /* Prepend a queue element (*i) to the head of the queue, after the queue head (*q).  The new queue element should not currently be on any list. */
00124 #define queue_Prepend(q,i) _RXQA(_RXQ(q),_RXQ(i),next,prev)
00125 
00126 /* Append a queue element (*i) to the end of the queue, before the queue head (*q).  The new queue element should not currently be on any list. */
00127 #define queue_Append(q,i) _RXQA(_RXQ(q),_RXQ(i),prev,next)
00128 
00129 /* Insert a queue element (*i2) before another element (*i1) in the queue.  The new queue element should not currently be on any list. */
00130 #define queue_InsertBefore(i1,i2) _RXQA(_RXQ(i1),_RXQ(i2),prev,next)
00131 
00132 /* Insert a queue element (*i2) after another element (*i1) in the queue.  The new queue element should not currently be on any list. */
00133 #define queue_InsertAfter(i1,i2) _RXQA(_RXQ(i1),_RXQ(i2),next,prev)
00134 
00135 /* Spice the members of (*q2) to the beginning of (*q1), re-initialize (*q2) */
00136 #define queue_SplicePrepend(q1,q2) _RXQS(_RXQ(q1),_RXQ(q2),next,prev)
00137 
00138 /* Splice the members of queue (*q2) to the end of (*q1), re-initialize (*q2) */
00139 #define queue_SpliceAppend(q1,q2) _RXQS(_RXQ(q1),_RXQ(q2),prev,next)
00140 
00141 /* split the members after i off of queue (*q1), and append them onto queue (*q2) */
00142 #define queue_SplitAfterAppend(q1,q2,i) _RXQSP(_RXQ(q1),_RXQ(q2),_RXQ(i),prev,next,next,prev,_RXQ(q1),_RXQ(i))
00143 
00144 /* split the members after i off of queue (*q1), and prepend them onto queue (*q2) */
00145 #define queue_SplitAfterPrepend(q1,q2,i) _RXQSP(_RXQ(q1),_RXQ(q2),_RXQ(i),next,prev,next,prev,_RXQ(i),_RXQ(q1))
00146 
00147 /* split the members before i off of queue (*q1), and append them onto queue (*q2) */
00148 #define queue_SplitBeforeAppend(q1,q2,i) _RXQSP(_RXQ(q1),_RXQ(q2),_RXQ(i),prev,next,prev,next,_RXQ(i),_RXQ(q1))
00149 
00150 /* split the members before i off of queue (*q1), and prepend them onto queue (*q2) */
00151 #define queue_SplitBeforePrepend(q1,q2,i) _RXQSP(_RXQ(q1),_RXQ(q2),_RXQ(i),next,prev,prev,next,_RXQ(q1),_RXQ(i))
00152 
00153 /* Replace the queue (*q1) with the contents of the queue (*q2), re-initialize (*q2) */
00154 #define queue_Replace(q1,q2) \
00155         do { \
00156             if (queue_IsEmpty(q2)) \
00157                 queue_Init(q1); \
00158             else { \
00159                 *_RXQ(q1) = *_RXQ(q2); \
00160                 _RXQ(q1)->next->prev = _RXQ(q1)->prev->next = _RXQ(q1); \
00161                 queue_Init(q2); \
00162             } \
00163         } while (0)
00164 
00165 /* move a chain of elements beginning at (s) and ending at (e) before node (i) */
00166 #define queue_MoveChainBefore(i, s, e) _RXQMV(_RXQ(i),_RXQ(s),_RXQ(e),prev,next,_RXQ(s),_RXQ(e))
00167 
00168 /* move a chain of elements beginning at (s) and ending at (e) after node (i) */
00169 #define queue_MoveChainAfter(i, s, e) _RXQMV(_RXQ(i),_RXQ(s),_RXQ(e),next,prev,_RXQ(e),_RXQ(s))
00170 
00171 /* Remove a queue element (*i) from its queue.  The next field is 0'd, so that any further use of this q entry will hopefully cause a core dump.  Multiple removes of the same queue item are not supported */
00172 #define queue_Remove(i) \
00173         do { \
00174             _RXQR(i); \
00175             _RXQ(i)->next = NULL; \
00176         } while (0)
00177 
00178 /* Move the queue element (*i) from its queue to the end of the queue (*q) */
00179 #define queue_MoveAppend(q,i) \
00180         do { \
00181             _RXQR(i); \
00182             queue_Append(q, i); \
00183         } while (0)
00184 
00185 /* Move the queue element (*i) from its queue to the head of the queue (*q) */
00186 #define queue_MovePrepend(q,i) \
00187         do { \
00188             _RXQR(i); \
00189             queue_Prepend(q, i); \
00190         } while (0)
00191 
00192 /* Return the first element of a queue, coerced too the specified structure s */
00193 /* Warning:  this returns the queue head, if the queue is empty */
00194 #define queue_First(q,s) ((struct s *)_RXQ(q)->next)
00195 
00196 /* Return the last element of a queue, coerced to the specified structure s */
00197 /* Warning:  this returns the queue head, if the queue is empty */
00198 #define queue_Last(q,s) ((struct s *)_RXQ(q)->prev)
00199 
00200 /* Return the next element in a queue, beyond the specified item, coerced to the specified structure s */
00201 /* Warning:  this returns the queue head, if the item specified is the last in the queue */
00202 #define queue_Next(i,s) ((struct s *)_RXQ(i)->next)
00203 
00204 /* Return the previous element to a specified element of a queue, coerced to the specified structure s */
00205 /* Warning:  this returns the queue head, if the item specified is the first in the queue */
00206 #define queue_Prev(i,s) ((struct s *)_RXQ(i)->prev)
00207 
00208 /* Return true if the queue is empty, i.e. just consists of a queue head.  The queue head must have been initialized some time prior to this call */
00209 #define queue_IsEmpty(q) (_RXQ(q)->next == _RXQ(q))
00210 
00211 /* Return true if the queue is non-empty, i.e. consists of a queue head plus at least one queue item */
00212 #define queue_IsNotEmpty(q) (_RXQ(q)->next != _RXQ(q))
00213 
00214 /* Return true if the queue item is currently in a queue */
00215 /* Returns false if the item was removed from a queue OR is uninitialized (zero) */
00216 #define queue_IsOnQueue(i) (_RXQ(i)->next != 0)
00217 
00218 /* Returns true if the item was removed from a queue OR is uninitialized (zero) */
00219 /* Return false if the queue item is currently in a queue */
00220 #define queue_IsNotOnQueue(i) (_RXQ(i)->next == 0)
00221 
00222 /* Returns true if the queue item (i) is the first element of the queue (q) */
00223 #define queue_IsFirst(q,i) (_RXQ(q)->first == _RXQ(i))
00224 
00225 /* Returns true if the queue item (i) is the last element of the queue (q) */
00226 #define queue_IsLast(q,i) (_RXQ(q)->prev == _RXQ(i))
00227 
00228 /* Returns true if the queue item (i) is the end of the queue (q), that is, i is the head of the queue */
00229 #define queue_IsEnd(q,i) (_RXQ(q) == _RXQ(i))
00230 
00231 /* Returns false if the queue item (i) is the end of the queue (q), that is, i is the head of the queue */
00232 #define queue_IsNotEnd(q,i) (_RXQ(q) != _RXQ(i))
00233 
00234 /* Prototypical loop to scan an entire queue forwards.  q is the queue
00235  * head, qe is the loop variable, next is a variable used to store the
00236  * queue entry for the next iteration of the loop, s is the user's
00237  * queue structure name.  Called using "for (queue_Scan(...)) {...}".
00238  * Note that extra initializers can be added before the queue_Scan,
00239  * and additional expressions afterwards.  So "for (sum=0,
00240  * queue_Scan(...), sum += value) {value = qe->value}" is possible.
00241  * If the current queue entry is deleted, the loop will work
00242  * correctly.  Care must be taken if other elements are deleted or
00243  * inserted.  Next may be updated within the loop to alter the item
00244  * used in the next iteration. */
00245 #define queue_Scan(q, qe, next, s)                      \
00246     (qe) = queue_First(q, s), next = queue_Next(qe, s); \
00247         !queue_IsEnd(q, qe);                            \
00248         (qe) = (next), next = queue_Next(qe, s)
00249 
00250 /* similar to queue_Scan except start at element 'start' instead of the beginning */
00251 #define        queue_ScanFrom(q, start, qe, next, s)      \
00252     (qe) = (struct s*)(start), next = queue_Next(qe, s);  \
00253        !queue_IsEnd(q, qe);                               \
00254        (qe) = (next), next = queue_Next(qe, s)
00255 
00256 /* This is similar to queue_Scan, but scans from the end of the queue to the beginning.  Next is the previous queue entry.  */
00257 #define queue_ScanBackwards(q, qe, prev, s)             \
00258     (qe) = queue_Last(q, s), prev = queue_Prev(qe, s);  \
00259         !queue_IsEnd(q, qe);                            \
00260         (qe) = prev, prev = queue_Prev(qe, s)
00261 
00262 /* This is similar to queue_ScanBackwards, but start at element 'start' instead of the end.  Next is the previous queue entry.  */
00263 #define        queue_ScanBackwardsFrom(q, start, qe, prev, s)  \
00264     (qe) = (struct s*)(start), prev = queue_Prev(qe, s);       \
00265        !queue_IsEnd(q, qe);                                    \
00266        (qe) = prev, prev = queue_Prev(qe, s)
00267 
00268 #define queue_Count(q, qe, nqe, s, n)                   \
00269     for (n=0, queue_Scan(q, qe, nqe, s), n++) {}
00270 #endif /* _RX_QUEUE_ */
 All Data Structures Files Functions Variables