/* FIFO queue package (W) Copywrong 1980 Scott W. Layson These cute little routines implement First In, First Out queues. There are complete sets of routines provided: one to handle integer-sized (2-byte) objects, and the other to handle byte-sized things. The routines are good for applications such as I/O buffering in programs that do several things at once. For example, consider the following program fragment (remember that all this text is one big comment!): #define KBD_Q_SIZE 40 struct cqueue { char *cruft[4], space[KBD_Q_SIZE]; } kbd_q; / * This program eats command characters and does something hairy with them * / main() { <... assorted declarations ...> CQInit (&kbd_q, KBD_Q_SIZE); while (1) do { cmd = get_qd_char(); hairily_process (cmd); } } / * Return a character off the queue if there are any, otherwise wait for one to be typed * / get_qd_char() { if (!CQEmpty(&kbd_q) return CQGrab(&kbd_q); else return getchar(); } / * If a character has been typed, queue it * / kbd_check() { if (kbhit()) CQShove (getchar(), &kbd_q); } Careful scattering of calls to kbd_check throughout hairily_process() will prevent keyboard characters from being missed no matter how far the user types ahead (up to the KBD_Q_SIZE, of course). Small misfeature: the queue will actually hold one fewer object than the size allocated for it. E.g., the above kbd_q will hold (KBD_Q_SIZE - 1) characters. This usually doesn't matter, as usual practice is just to make a queue much larger than it really has to be anyway. ************** End of comments **********************************/ struct queue { int *head, *tail, *top, *bottom, space; }; /* Initialization routine (must be called before any operation is done on the queue) */ QInit(queue_p,size) struct queue *queue_p; int size; { queue_p->head = queue_p->tail = queue_p->top = &(queue_p->space); queue_p->bottom = queue_p->top +size -1; } /* Routine to grab something off the head of a queue Does no error checking! Be careful of underflow! */ QGrab(queue_p) struct queue *queue_p; { return ((queue_p->head >= queue_p->bottom) ? *(queue_p->head = queue_p->top) : *++(queue_p->head)); } /* Routine to shove something onto the tail of a queue Does no error checking! BE careful of underflow! */ QShove(x,queue_p) struct queue *queue_p; int x; { *((queue_p->tail >= queue_p->bottom) ? (queue_p->tail = queue_p->top) : ++(queue_p->tail)) = x; } /* Emptiness predicate */ QEmpty(queue_p) struct queue *queue_p; { return (queue_p->head == queue_p->tail); } /* Fullness predicate */ QFull(queue_p) struct queue *queue_p; { return((queue_p->tail+1 == queue_p->head) || (queue_p->tail == queue_p->bottom && queue_p->head == queue_p->top)); } /* Peek at head of queue without disturbing it */ QPeek(queue_p) struct queue *queue_p; { return ( (queue_p->head == queue_p->bottom) ? *queue_p->top : *(queue_p->head + 1) ); } /* Here is the same repertoire of routines, but set up for characters instead of integers: */ struct cqueue { char *chead, *ctail, *ctop, *cbottom, cspace; }; /* Initialization routine (must be called before any operation done on the queue) */ CQInit(queue_p,size) struct cqueue *queue_p; int size; { queue_p->chead = queue_p->ctail = queue_p->ctop = &(queue_p->cspace); queue_p->cbottom = queue_p->ctop +size -1; } /* Routine to grab something off the head of a queue Does no error checking! Be careful of underflow! */ CQGrab(queue_p) struct cqueue *queue_p; { return ((queue_p->chead >= queue_p->cbottom) ? *(queue_p->chead = queue_p->ctop) : *++(queue_p->chead)); } /* Routine to shove something onto the tail of a queue Does no error checking! Be careful of overflow! */ CQShove(x,queue_p) struct cqueue *queue_p; int x; { *((queue_p->ctail >= queue_p->cbottom) ? (queue_p->ctail = queue_p->ctop) : ++(queue_p->ctail)) = x; } /* Emptiness predicate */ CQEmpty(queue_p) struct cqueue *queue_p; { return (queue_p->chead == queue_p->ctail); } /* Fullness predicate */ CQFull(queue_p) struct cqueue *queue_p; { return((queue_p->ctail+1 == queue_p->chead) || (queue_p->ctail == queue_p->cbottom && queue_p->chead == queue_p->ctop)); } /* Peek at head of queue without disturbing it */ CQPeek(queue_p) struct cqueue *queue_p; { return ( (queue_p->chead == queue_p->cbottom) ? *queue_p->ctop : queue_p->chead[1] ); }