]> git.ozlabs.org Git - ccan/blob - ccan/lqueue/lqueue.h
15d242ef127349f06882c697d201d8d01ff2f265
[ccan] / ccan / lqueue / lqueue.h
1 /* Licensed under BSD-MIT - see LICENSE file for details */
2 #ifndef CCAN_LQUEUE_H
3 #define CCAN_LQUEUE_H
4
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <assert.h>
8
9 #include <ccan/container_of/container_of.h>
10
11 /**
12  * struct lqueue_link - a queue link
13  * @next: next entry, or front of queue, if this is the back
14  *
15  * This is used as a link within a queue entry.
16  *
17  * Example:
18  *      struct waiter {
19  *              char *name;
20  *              struct lqueue_link ql;
21  *      };
22  */
23 struct lqueue_link {
24         struct lqueue_link *next;
25 };
26
27 /**
28  * struct lqueue - the head of a queue
29  * @b: the back of the queue (NULL if empty)
30  */
31 struct lqueue {
32         struct lqueue_link *back;
33 };
34
35 /**
36  * LQUEUE - define and initialize an empty queue
37  * @name: the name of the lqueue.
38  *
39  * The LQUEUE macro defines an lqueue and initializes it to an empty
40  * queue.  It can be prepended by "static" to define a static lqueue.
41  *
42  * See also:
43  *      lqueue_init()
44  *
45  * Example:
46  *      LQUEUE(my_queue);
47  *
48  *      assert(lqueue_empty(&my_queue));
49  */
50 #define LQUEUE(name) \
51         struct lqueue name = { NULL, }
52
53 /**
54  * lqueue_init - initialize a queue
55  * @h: the lqueue to set to an empty queue
56  *
57  * Example:
58  *      struct lqueue *qp = malloc(sizeof(*qp));
59  *      lqueue_init(qp);
60  */
61 static inline void lqueue_init(struct lqueue *q)
62 {
63         q->back = NULL;
64 }
65
66 /**
67  * lqueue_empty - is a queue empty?
68  * @q: the queue
69  *
70  * If the queue is empty, returns true.
71  *
72  * Example:
73  *      assert(lqueue_empty(qp));
74  */
75 static inline bool lqueue_empty(const struct lqueue *q)
76 {
77         return (q->back == NULL);
78 }
79
80 /**
81  * lqueue_entry - convert an lqueue_link back into the structure containing it.
82  * @e: the lqueue_link
83  * @type: the type of the entry
84  * @member: the lqueue_link member of the type
85  *
86  * Example:
87  *      struct waiter {
88  *              char *name;
89  *              struct lqueue_link ql;
90  *      } w;
91  *      assert(lqueue_entry(&w.ql, struct waiter, ql) == &w);
92  */
93 #define lqueue_entry(n, type, member) container_of_or_null(n, type, member)
94
95 /**
96  * lqueue_front - get front entry in a queue
97  * @q: the queue
98  * @type: the type of queue entries
99  * @member: the lqueue_link entry
100  *
101  * If the queue is empty, returns NULL.
102  *
103  * Example:
104  *      struct waiter *f;
105  *
106  *      f = lqueue_front(qp, struct waiter, ql);
107  *      assert(lqueue_dequeue(qp, struct waiter, ql) == f);
108  */
109 #define lqueue_front(q, type, member) \
110         lqueue_entry(lqueue_front_((q)), type, member)
111 static inline struct lqueue_link *lqueue_front_(const struct lqueue *q)
112 {
113         if (!q->back)
114                 return NULL;
115         else
116                 return q->back->next;
117 }
118
119 /**
120  * lqueue_back - get back entry in a queue
121  * @q: the queue
122  * @type: the type of queue entries
123  * @member: the lqueue_link entry
124  *
125  * If the queue is empty, returns NULL.
126  *
127  * Example:
128  *      struct waiter b;
129  *
130  *      lqueue_enqueue(qp, &b, ql);
131  *      assert(lqueue_back(qp, struct waiter, ql) == &b);
132  */
133 #define lqueue_back(q, type, member) \
134         lqueue_entry(lqueue_back_((q)), type, member)
135 static inline struct lqueue_link *lqueue_back_(const struct lqueue *q)
136 {
137         return q->back;
138 }
139
140 /**
141  * lqueue_enqueue - add an entry to the back of a queue
142  * @q: the queue to add the node to
143  * @e: the item to enqueue
144  * @member: the lqueue_link field of *e
145  *
146  * The lqueue_link does not need to be initialized; it will be overwritten.
147  */
148 #define lqueue_enqueue(q, e, member) \
149         lqueue_enqueue_((q), &((e)->member))
150 static inline void lqueue_enqueue_(struct lqueue *q, struct lqueue_link *e)
151 {
152         if (lqueue_empty(q)) {
153                 /* New entry will be both front and back of queue */
154                 e->next = e;
155                 q->back = e;
156         } else {
157                 e->next = lqueue_front_(q);
158                 q->back->next = e;
159                 q->back = e;
160         }
161 }
162
163 /**
164  * lqueue_dequeue - remove and return the entry from the front of the queue
165  * @q: the queue
166  * @type: the type of queue entries
167  * @member: the lqueue_link field of @type
168  *
169  * Note that this leaves the returned entry's link in an undefined
170  * state; it can be added to another queue, but not deleted again.
171  */
172 #define lqueue_dequeue(q, type, member) \
173         lqueue_entry(lqueue_dequeue_((q)), type, member)
174 static inline struct lqueue_link *lqueue_dequeue_(struct lqueue *q)
175 {
176         struct lqueue_link *front;
177
178         if (lqueue_empty(q))
179                 return NULL;
180
181         front = lqueue_front_(q);
182         if (front == lqueue_back_(q)) {
183                 assert(front->next == front);
184                 q->back = NULL;
185         } else {
186                 q->back->next = front->next;
187         }
188         return front;
189 }
190
191 #endif /* CCAN_LQUEUE_H */