1 | /* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> |
2 | * |
3 | * Permission to use, copy, modify, and/or distribute this software for any |
4 | * purpose with or without fee is hereby granted, provided that the above |
5 | * copyright notice and this permission notice appear in all copies. |
6 | * |
7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
10 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
12 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
13 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | */ |
15 | |
16 | #ifndef QUEUE_H_ |
17 | #define QUEUE_H_ |
18 | |
19 | #include <stddef.h> |
20 | |
21 | typedef void *QUEUE[2]; |
22 | |
23 | /* Private macros. */ |
24 | #define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) |
25 | #define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) |
26 | #define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q))) |
27 | #define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q))) |
28 | |
29 | /* Public macros. */ |
30 | #define QUEUE_DATA(ptr, type, field) \ |
31 | ((type *) ((char *) (ptr) - offsetof(type, field))) |
32 | |
33 | /* Important note: mutating the list while QUEUE_FOREACH is |
34 | * iterating over its elements results in undefined behavior. |
35 | */ |
36 | #define QUEUE_FOREACH(q, h) \ |
37 | for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) |
38 | |
39 | #define QUEUE_EMPTY(q) \ |
40 | ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q)) |
41 | |
42 | #define QUEUE_HEAD(q) \ |
43 | (QUEUE_NEXT(q)) |
44 | |
45 | #define QUEUE_INIT(q) \ |
46 | do { \ |
47 | QUEUE_NEXT(q) = (q); \ |
48 | QUEUE_PREV(q) = (q); \ |
49 | } \ |
50 | while (0) |
51 | |
52 | #define QUEUE_ADD(h, n) \ |
53 | do { \ |
54 | QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \ |
55 | QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \ |
56 | QUEUE_PREV(h) = QUEUE_PREV(n); \ |
57 | QUEUE_PREV_NEXT(h) = (h); \ |
58 | } \ |
59 | while (0) |
60 | |
61 | #define QUEUE_SPLIT(h, q, n) \ |
62 | do { \ |
63 | QUEUE_PREV(n) = QUEUE_PREV(h); \ |
64 | QUEUE_PREV_NEXT(n) = (n); \ |
65 | QUEUE_NEXT(n) = (q); \ |
66 | QUEUE_PREV(h) = QUEUE_PREV(q); \ |
67 | QUEUE_PREV_NEXT(h) = (h); \ |
68 | QUEUE_PREV(q) = (n); \ |
69 | } \ |
70 | while (0) |
71 | |
72 | #define QUEUE_MOVE(h, n) \ |
73 | do { \ |
74 | if (QUEUE_EMPTY(h)) \ |
75 | QUEUE_INIT(n); \ |
76 | else { \ |
77 | QUEUE* q = QUEUE_HEAD(h); \ |
78 | QUEUE_SPLIT(h, q, n); \ |
79 | } \ |
80 | } \ |
81 | while (0) |
82 | |
83 | #define QUEUE_INSERT_HEAD(h, q) \ |
84 | do { \ |
85 | QUEUE_NEXT(q) = QUEUE_NEXT(h); \ |
86 | QUEUE_PREV(q) = (h); \ |
87 | QUEUE_NEXT_PREV(q) = (q); \ |
88 | QUEUE_NEXT(h) = (q); \ |
89 | } \ |
90 | while (0) |
91 | |
92 | #define QUEUE_INSERT_TAIL(h, q) \ |
93 | do { \ |
94 | QUEUE_NEXT(q) = (h); \ |
95 | QUEUE_PREV(q) = QUEUE_PREV(h); \ |
96 | QUEUE_PREV_NEXT(q) = (q); \ |
97 | QUEUE_PREV(h) = (q); \ |
98 | } \ |
99 | while (0) |
100 | |
101 | #define QUEUE_REMOVE(q) \ |
102 | do { \ |
103 | QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \ |
104 | QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \ |
105 | } \ |
106 | while (0) |
107 | |
108 | #endif /* QUEUE_H_ */ |
109 | |