5 // Created by pete on 1/29/16.
6 // Copyright © 2016-2020 Pete. All rights reserved.
19 simpleQueues 1.0v4 [May 3 2020]
20 - changed the qBlock header to include an int64 key
21 - added an insert blcok in order function
27 - rebuild of old code with old testing harness and new names for the API
28 - we no longer try to keep count of the elements in a queue
31 - now #include types.h from the utilities project
32 - now include utilities.c and .h to provide timenow()
35 - changed qAppendQTail and qAppendQHead to NOT free the Queue structure that's supplying the list
38 - changed Queue * qNewQs(uint64 count, char * name) to check for the existence of the malloc'd queues before initialising them
42 static char * name_and_version
= "simpleQueues 1.0v4 [May 3 2020]";
44 // ---------------------- qNameAndVersion --------------
46 char * qNameAndVersion(void) {
47 return name_and_version
;
50 // ------------------ qError ---------------
52 void qError(char * msg
, char * s1
, char * s2
) {
53 printf("\n\n==qERROR: %s %s %s\n", msg
, s1
? s1
: "", s2
? s2
: "");
56 // ------------------ qCheckQ ------------------
58 uint32
qCheckQ(Queue
* q
) {
59 // checks the specified queue for consistency
60 uint32 errors
= qCheckSlice("queue", q
-> head
, q
-> tail
);
65 // ------------------ qCheckSlice ------------------
67 uint32
qCheckSlice(char * msg
, qBlock
* b0
, qBlock
* b1
) {
68 // checks the specified slice of blocks for consistency
70 qBlock
* front
, * back
;
71 uint32 fwd
= 0, bwd
= 0;
75 // check going from front arrives at back
76 while (b0
&& (b0
!= back
)) {
81 printf("\n\terror in traversing %s forward from %p..%p", msg
, front
, back
);
85 // check going from back to front arrives at front
87 while (b0
&& (b0
!= front
)) {
93 printf("\n\terror in traversing %s backward from %p..%p", msg
, front
, back
);
98 printf("\n\tcount error in traversing %s from %p..%p; fwdcount=%d, bwdcount=%d", msg
, front
, back
, fwd
, bwd
);
104 // ------------------ qCountQ ----------------------
106 uint64
qCountQ(Queue
* q
) {
123 // ------------------ qSetQEmpty ----------------
125 void qSetQEmpty(Queue
* q
) {
130 // -------------------------- qInitQ --------------------------
132 void qInitQ(Queue
* q
, char * name
, uint64 n
) {
133 // initialise created queue
135 int l
= (int)strlen(name
);
136 q
-> qname
= malloc(l
+ 16);
137 sprintf(q
-> qname
, "%s[%llu]", name
, n
);
139 else q
-> qname
= NULL
;
146 //// --------------- qSetQType -------------
148 //void qSetQType(Queue * q, blockType bt) {
150 // uint64 size = strlen(q -> qname) + strlen(btName(bt)) + 16;
151 // char * n = malloc(size);
152 // strcpy(n, q -> qname);
154 // strcat(n, btName(bt));
156 // //printf("\nqSetQType: freeing '%s' and setting '%s'", q -> qname, n);
161 // -------------------------- qNewQ ---------------------------
163 Queue
* qNewQ(char * name
) {
164 // create and initialise just one queue
165 return qNewQs(1, name
);
168 // -------------------------- qNewQs -------------------------
170 Queue
* qNewQs(uint64 count
, char * name
) {
171 // creates and initialises an array of 'count' queues
174 q
= malloc(count
* sizeof(Queue
));
176 for (i
= 0; i
< count
; i
++) {
177 qInitQ(&q
[i
], name
, i
);
183 // -------------------------- qKillQs ------------------------
185 void qKillQs(Queue
* qs
, uint64 count
) {
186 // kills the array of count queues at q
190 // ------------------------- qKillQEntries --------------------------
192 void qKillQEntries(Queue
* q
) {
193 // removes and frees all entries on the specified queue
194 // must ONLY be used when the blocks were malloc()'d
195 // does not free any memory associated with the blocks
204 // --------------------------- AddQHead ---------------------------
206 void qAddQHead(Queue
* q
, qBlock
* start
, qBlock
* end
) {
207 // adds the list of blocks to the head of q
209 start
-> prev
= NULL
;
210 end
-> next
= q
-> head
;
212 // the queue is non-empty
213 q
-> head
-> prev
= end
;
224 // ---------------------------- qAddQTail -------------------------
226 void qAddQTail(Queue
* q
, qBlock
* start
, qBlock
* end
) {
227 // adds the list of blocks to the tail of q
230 start
-> prev
= q
-> tail
;
232 // the queue is non-empty
233 q
-> tail
-> next
= start
;
237 // the queue is empty
245 // --------------------------- qAppendQTail --------------------
247 void qAppendQTail(Queue
* qd
, Queue
* qs
) {
248 // places all the elements of qs on the tail of qd
249 qBlock
* start
, *end
;
250 start
= qFirstBlock(qs
);
251 end
= qLastBlock(qs
);
253 qCutQ(qs
, start
, end
);
254 qAddQTail(qd
, start
, end
);
257 // --------------------------- qAppendQHead --------------------
259 void qAppendQHead(Queue
* qd
, Queue
* qs
) {
260 // places all the elements of qs at the head of qd
261 qBlock
* start
, *end
;
262 start
= qFirstBlock(qs
);
263 end
= qLastBlock(qs
);
265 qCutQ(qs
, start
, end
);
266 qAddQHead(qd
, start
, end
);
269 // --------------------------- qCutQ -------------------------
271 void qCutQ(Queue
* q
, qBlock
* start
, qBlock
* end
) {
272 // cuts the blocks start..end out of queue q
273 if ((start
== NULL
) || (end
== NULL
)) {
274 return; // no action if no slice
276 if ((q
-> head
== start
) && (q
-> tail
== end
)) {
281 else if (q
-> head
== start
) {
282 // cut from start to some way down
283 q
-> head
= end
-> next
;
284 end
-> next
-> prev
= NULL
;
286 else if (q
-> tail
== end
) {
287 // cut from middle to end
288 q
-> tail
= start
-> prev
;
289 start
-> prev
-> next
= NULL
;
293 start
-> prev
-> next
= end
-> next
;
294 end
-> next
-> prev
= start
-> prev
;
298 // --------------------------- qCutBlock -------------------------
300 void qCutBlock(Queue
* q
, qBlock
* block
) {
301 // cuts the block 'block' out of queue q,
302 if (block
== NULL
) return;
304 if ((q
-> head
== block
) && (q
-> tail
== block
)) {
309 else if (q
-> head
== block
) {
310 // remove first block
311 q
-> head
= block
-> next
;
312 block
-> next
-> prev
= NULL
;
314 else if (q
-> tail
== block
) {
316 q
-> tail
= block
-> prev
;
317 block
-> prev
-> next
= NULL
;
321 block
-> prev
-> next
= block
-> next
;
322 block
-> next
-> prev
= block
-> prev
;
326 // --------------------------- qAddBlock -------------------------
328 void qAddBlock(Queue
* q
, qBlock
* block
) {
329 // add block to tail of queue
331 // if (q -> bt != btAny) {
332 // if (q -> bt != block -> bt) {
333 // qError("mismatched queue and block type", btName(q -> bt), btName(block -> bt));
337 block
-> next
= NULL
;
338 block
-> prev
= q
-> tail
;
341 q
-> tail
-> next
= block
;
352 // --------------------------- qAddBlockBefore -------------------------
354 void qAddBlockBefore(Queue
* q
, qBlock
* block
, qBlock
* here
) {
355 // add 'block' to queue immediately before block 'here'
356 // if q is empty, make block the q
357 // if 'here' is NULL, add to end
359 if (block
== NULL
) return;
360 if (qFirstBlock(q
) == NULL
) {
363 else if (here
== NULL
) {
364 // didn't find anywhere; just add to tail
367 else if (here
-> prev
== NULL
) {
369 qAddBlockHead(q
, block
);
372 // it's in the middle; chain in block after here->prev
373 qAddBlockAfter(q
, block
, here
->prev
);
377 // --------------------------- qAddBlockBeforeHead -------------------------
379 void qAddBlockBeforeHead(Queue
* q
, qBlock
* block
, qBlock
* here
) {
380 // add 'block' to queue immediately before block 'here'
381 // if q is empty, make block the q
382 // if 'here' is NULL, add to head
384 if (block
== NULL
) return;
385 if (qFirstBlock(q
) == NULL
) {
388 else if ((here
== NULL
) || (here
-> prev
== NULL
)) {
390 qAddBlockHead(q
, block
);
393 // it's in the middle; chain in block after here->prev
394 qAddBlockAfter(q
, block
, here
->prev
);
398 // --------------------------- AddBlockAfter -------------------------
400 void qAddBlockAfter(Queue
* q
, qBlock
* block
, qBlock
* here
) {
401 // add block to queue immediately after block here
403 if (block
== NULL
) return;
404 if (qFirstBlock(q
) == NULL
) {
405 // no queue: add to head
406 qAddBlockHead(q
, block
);
408 else if ((here
== NULL
) || (here
-> next
== NULL
)) {
409 // no place to add, or 'here' is the tail of the queue, so add to tail
413 // 'here' is in the middle; chain in block after here
417 block
-> next
= next
;
418 block
-> prev
= here
;
419 here
-> next
= block
;
420 next
-> prev
= block
;
424 // --------------------------- qAddBlockAfterHead -------------------------
426 void qAddBlockAfterHead(Queue
* q
, qBlock
* block
, qBlock
* here
) {
427 // add block to queue immediately after block here
428 // add to front of queue if 'here' is NULL
430 if (block
== NULL
) return;
431 if ((qFirstBlock(q
) == NULL
) || (here
== NULL
)) {
432 // no queue: add to head
433 qAddBlockHead(q
, block
);
435 else if (here
== q
-> tail
) {
436 // add to tail in normal manner
440 // 'here' is in the middle; chain in block after here
444 block
-> next
= next
;
445 block
-> prev
= here
;
446 here
-> next
= block
;
447 next
-> prev
= block
;
451 void printSymQ(char * msg
, void * st
, Queue
* q
);
453 // --------------------------- qAddBlockHead -------------------------
455 void qAddBlockHead(Queue
* q
, qBlock
* block
) {
457 // there's something wrong with this
459 // add block to FRONT of queue
460 if (block
== NULL
) return;
462 qBlock
* head
= qFirst(q
);
465 // non-empty queue. point old head at new block. don't touch tail.
466 head
-> prev
= block
;
467 // point new block at old head
468 block
-> next
= head
;
469 // make it have no prevs
470 block
-> prev
= NULL
;
471 // set block as the head.
481 // ----------------------- qGetBlockTail ----------------
483 qBlock
* qGetBlockTail(Queue
* q
) {
484 // gets the tail of the queue
485 qBlock
* block
= q
-> tail
;
489 // ---------------------------- qGetBlock ----------------------
491 qBlock
* qGetBlock(Queue
* q
) {
492 // removes the first block on 'q' and returns it
499 if (q
-> tail
== block
) {
500 // just one in queue; empty the queue
501 qSetQEmpty(q
); // empty the queue
504 q
-> head
= block
-> next
; // move head
505 block
-> next
-> prev
= NULL
; // mark new head
511 // -------------------------- qPushBlock ----------------------
513 void qPushBlock(Queue
* q
,qBlock
* block
) {
514 // push and pop run a queue as a stack; push puts block on front of queue
515 qAddBlockHead(q
, block
);
518 // -------------------------- qPushBlock ----------------------
520 qBlock
* qPopBlock(Queue
* q
) {
521 // push and pop run a queue as a stack; pop gets block from front of queue
525 // --------------------------- qInitBlock ---------------------
527 void qInitBlock(qBlock
* block
) {
528 // initialise block pointers to values which will surely trap if used
529 block
-> next
= NULL
;
530 block
-> prev
= NULL
;
531 // block -> bt = btAny;
535 //// ----------------- qSetBlockType ---------------
537 //void qSetBlockType(qBlock * b, blockType bt) {
541 // --------------------------- qNewBlock -----------------------
543 void * qNewBlock(uint32 size
) {
544 // creates and initialises a new block of the desired size
545 qBlock
* block
= malloc(size
);
546 if (block
) qInitBlock(block
);
550 // ------------- qInsertKeyBlockInOrder --------------
552 void qInsertBlockInOrder(Queue
* q
, qBlock
* block
) {
553 // q is a key-ordered queue of qKeyBlocks
554 // it is not in any queue (pointers are NULL)
555 // run down the queue looking for the insertion point, which is
556 // in front of the first block with the same or later time
558 // if (block -> key < 300) printf("\n--qInsertKeyBlockInOrder: block %p time %lld", block, block -> key);
559 qBlock
* here
= qFirst(q
);
561 // if (block -> key < 300) printf("\n\tchecking block %p at time %lld", here, here -> key);
562 if (here
-> key
>= block
-> key
) break;
567 // insert before here
568 // if (block -> key < 300) printf("\n\t.. insert before block %p key %lld", here, here -> key);
569 qAddBlockBefore(q
, block
, here
);
573 // if (block -> key < 300) printf("\t.. add to tail");
577 // ------------- qPrintKeyQ ---------------
579 void qPrintKeyQ(Queue
* q
) {
580 printf("\nKey Queue %p '%s'", q
, q
-> qname
);
581 qBlock
* b
= qFirst(q
);
583 printf("\n\tblock %p has key %lld", b
, b
-> key
);