|
@@ -6,7 +6,7 @@
|
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
|
#include <assert.h>
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
-#include <ccan/container_of/container_of.h>
|
|
|
|
|
|
|
+#include <ccan/tcon/tcon.h>
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* struct lqueue_link - a queue link
|
|
* struct lqueue_link - a queue link
|
|
@@ -25,36 +25,74 @@ struct lqueue_link {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * struct lqueue - the head of a queue
|
|
|
|
|
|
|
+ * struct lqueue_ - a queue (internal type)
|
|
|
* @b: the back of the queue (NULL if empty)
|
|
* @b: the back of the queue (NULL if empty)
|
|
|
*/
|
|
*/
|
|
|
-struct lqueue {
|
|
|
|
|
|
|
+struct lqueue_ {
|
|
|
struct lqueue_link *back;
|
|
struct lqueue_link *back;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * LQUEUE - define and initialize an empty queue
|
|
|
|
|
- * @name: the name of the lqueue.
|
|
|
|
|
|
|
+ * LQUEUE - declare a queue
|
|
|
|
|
+ * @type: the type of elements in the queue
|
|
|
|
|
+ * @link: the field containing the lqueue_link in @type
|
|
|
*
|
|
*
|
|
|
- * The LQUEUE macro defines an lqueue and initializes it to an empty
|
|
|
|
|
- * queue. It can be prepended by "static" to define a static lqueue.
|
|
|
|
|
|
|
+ * The LQUEUE macro declares an lqueue. It can be prepended by
|
|
|
|
|
+ * "static" to define a static lqueue. The queue begins in undefined
|
|
|
|
|
+ * state, you must either initialize with LQUEUE_INIT, or call
|
|
|
|
|
+ * lqueue_init() before using it.
|
|
|
*
|
|
*
|
|
|
* See also:
|
|
* See also:
|
|
|
* lqueue_init()
|
|
* lqueue_init()
|
|
|
*
|
|
*
|
|
|
* Example:
|
|
* Example:
|
|
|
- * LQUEUE(my_queue);
|
|
|
|
|
|
|
+ * struct element {
|
|
|
|
|
+ * int value;
|
|
|
|
|
+ * struct lqueue_link link;
|
|
|
|
|
+ * };
|
|
|
|
|
+ * LQUEUE(struct element, link) my_queue;
|
|
|
|
|
+ */
|
|
|
|
|
+#define LQUEUE(etype, link) \
|
|
|
|
|
+ TCON_WRAP(struct lqueue_, \
|
|
|
|
|
+ TCON_CONTAINER(canary, etype, link))
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * LQUEUE_INIT - initializer for an empty queue
|
|
|
|
|
+ *
|
|
|
|
|
+ * The LQUEUE_INIT macro returns a suitable initializer for a queue
|
|
|
|
|
+ * defined with LQUEUE.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Example:
|
|
|
|
|
+ * struct element {
|
|
|
|
|
+ * int value;
|
|
|
|
|
+ * struct lqueue_link link;
|
|
|
|
|
+ * };
|
|
|
|
|
+ * LQUEUE(struct element, link) my_queue = LQUEUE_INIT;
|
|
|
*
|
|
*
|
|
|
* assert(lqueue_empty(&my_queue));
|
|
* assert(lqueue_empty(&my_queue));
|
|
|
*/
|
|
*/
|
|
|
-#define LQUEUE(name) \
|
|
|
|
|
- struct lqueue name = { NULL, }
|
|
|
|
|
|
|
+#define LQUEUE_INIT \
|
|
|
|
|
+ TCON_WRAP_INIT({ NULL, })
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * lqueue_entry - convert an lqueue_link back into the structure containing it.
|
|
|
|
|
+ * @q: the queue
|
|
|
|
|
+ * @l: the lqueue_link
|
|
|
|
|
+ *
|
|
|
|
|
+ * Example:
|
|
|
|
|
+ * struct waiter {
|
|
|
|
|
+ * char *name;
|
|
|
|
|
+ * struct lqueue_link ql;
|
|
|
|
|
+ * } w;
|
|
|
|
|
+ * LQUEUE(struct waiter, ql) my_queue;
|
|
|
|
|
+ * assert(lqueue_entry(&my_queue, &w.ql) == &w);
|
|
|
|
|
+ */
|
|
|
|
|
+#define lqueue_entry(q_, l_) tcon_container_of((q_), canary, (l_))
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* lqueue_init_from_back - initialize a queue with a specific back element
|
|
* lqueue_init_from_back - initialize a queue with a specific back element
|
|
|
* @s: the lqueue to initialize
|
|
* @s: the lqueue to initialize
|
|
|
* @e: pointer to the back element of the new queue
|
|
* @e: pointer to the back element of the new queue
|
|
|
- * @member: member of the element containing the lqueue_link
|
|
|
|
|
*
|
|
*
|
|
|
* USE WITH CAUTION: This is for handling unusual cases where you have
|
|
* USE WITH CAUTION: This is for handling unusual cases where you have
|
|
|
* a pointer to an element in a previously constructed queue but can't
|
|
* a pointer to an element in a previously constructed queue but can't
|
|
@@ -62,32 +100,35 @@ struct lqueue {
|
|
|
* should use lqueue_init().
|
|
* should use lqueue_init().
|
|
|
*
|
|
*
|
|
|
* Example:
|
|
* Example:
|
|
|
- * LQUEUE(queue1);
|
|
|
|
|
- * struct lqueue queue2;
|
|
|
|
|
* struct element {
|
|
* struct element {
|
|
|
* int value;
|
|
* int value;
|
|
|
* struct lqueue_link link;
|
|
* struct lqueue_link link;
|
|
|
* } el;
|
|
* } el;
|
|
|
|
|
+ * LQUEUE(struct element, link) queue1;
|
|
|
|
|
+ * LQUEUE(struct element, link) queue2;
|
|
|
*
|
|
*
|
|
|
- * lqueue_enqueue(&queue1, &el, link);
|
|
|
|
|
|
|
+ * lqueue_enqueue(&queue1, &el);
|
|
|
*
|
|
*
|
|
|
- * lqueue_init_from_back(&queue2,
|
|
|
|
|
- * lqueue_back(&queue1, struct element, link), link);
|
|
|
|
|
|
|
+ * lqueue_init_from_back(&queue2, lqueue_back(&queue1));
|
|
|
*/
|
|
*/
|
|
|
-#define lqueue_init_from_back(s, e, member) \
|
|
|
|
|
- (lqueue_init_((s), &(e)->member))
|
|
|
|
|
|
|
+#define lqueue_init_from_back(q_, e_) \
|
|
|
|
|
+ (lqueue_init_(tcon_unwrap(q_), tcon_member_of((q_), canary, (e_))))
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* lqueue_init - initialize a queue
|
|
* lqueue_init - initialize a queue
|
|
|
* @h: the lqueue to set to an empty queue
|
|
* @h: the lqueue to set to an empty queue
|
|
|
*
|
|
*
|
|
|
* Example:
|
|
* Example:
|
|
|
- * struct lqueue *qp = malloc(sizeof(*qp));
|
|
|
|
|
|
|
+ * struct element {
|
|
|
|
|
+ * int value;
|
|
|
|
|
+ * struct lqueue_link link;
|
|
|
|
|
+ * };
|
|
|
|
|
+ * LQUEUE(struct element, link) *qp = malloc(sizeof(*qp));
|
|
|
* lqueue_init(qp);
|
|
* lqueue_init(qp);
|
|
|
*/
|
|
*/
|
|
|
-#define lqueue_init(s) \
|
|
|
|
|
- (lqueue_init_((s), NULL))
|
|
|
|
|
-static inline void lqueue_init_(struct lqueue *q, struct lqueue_link *back)
|
|
|
|
|
|
|
+#define lqueue_init(q_) \
|
|
|
|
|
+ (lqueue_init_(tcon_unwrap(q_), NULL))
|
|
|
|
|
+static inline void lqueue_init_(struct lqueue_ *q, struct lqueue_link *back)
|
|
|
{
|
|
{
|
|
|
q->back = back;
|
|
q->back = back;
|
|
|
}
|
|
}
|
|
@@ -97,47 +138,29 @@ static inline void lqueue_init_(struct lqueue *q, struct lqueue_link *back)
|
|
|
* @q: the queue
|
|
* @q: the queue
|
|
|
*
|
|
*
|
|
|
* If the queue is empty, returns true.
|
|
* If the queue is empty, returns true.
|
|
|
- *
|
|
|
|
|
- * Example:
|
|
|
|
|
- * assert(lqueue_empty(qp));
|
|
|
|
|
*/
|
|
*/
|
|
|
-static inline bool lqueue_empty(const struct lqueue *q)
|
|
|
|
|
|
|
+#define lqueue_empty(q_) \
|
|
|
|
|
+ lqueue_empty_(tcon_unwrap(q_))
|
|
|
|
|
+static inline bool lqueue_empty_(const struct lqueue_ *q)
|
|
|
{
|
|
{
|
|
|
return (q->back == NULL);
|
|
return (q->back == NULL);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/**
|
|
|
|
|
- * lqueue_entry - convert an lqueue_link back into the structure containing it.
|
|
|
|
|
- * @e: the lqueue_link
|
|
|
|
|
- * @type: the type of the entry
|
|
|
|
|
- * @member: the lqueue_link member of the type
|
|
|
|
|
- *
|
|
|
|
|
- * Example:
|
|
|
|
|
- * struct waiter {
|
|
|
|
|
- * char *name;
|
|
|
|
|
- * struct lqueue_link ql;
|
|
|
|
|
- * } w;
|
|
|
|
|
- * assert(lqueue_entry(&w.ql, struct waiter, ql) == &w);
|
|
|
|
|
- */
|
|
|
|
|
-#define lqueue_entry(n, type, member) container_of_or_null(n, type, member)
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* lqueue_front - get front entry in a queue
|
|
* lqueue_front - get front entry in a queue
|
|
|
* @q: the queue
|
|
* @q: the queue
|
|
|
- * @type: the type of queue entries
|
|
|
|
|
- * @member: the lqueue_link entry
|
|
|
|
|
*
|
|
*
|
|
|
* If the queue is empty, returns NULL.
|
|
* If the queue is empty, returns NULL.
|
|
|
*
|
|
*
|
|
|
* Example:
|
|
* Example:
|
|
|
- * struct waiter *f;
|
|
|
|
|
|
|
+ * struct element *f;
|
|
|
*
|
|
*
|
|
|
- * f = lqueue_front(qp, struct waiter, ql);
|
|
|
|
|
- * assert(lqueue_dequeue(qp, struct waiter, ql) == f);
|
|
|
|
|
|
|
+ * f = lqueue_front(qp);
|
|
|
|
|
+ * assert(lqueue_dequeue(qp) == f);
|
|
|
*/
|
|
*/
|
|
|
-#define lqueue_front(q, type, member) \
|
|
|
|
|
- lqueue_entry(lqueue_front_((q)), type, member)
|
|
|
|
|
-static inline struct lqueue_link *lqueue_front_(const struct lqueue *q)
|
|
|
|
|
|
|
+#define lqueue_front(q_) \
|
|
|
|
|
+ lqueue_entry((q_), lqueue_front_(tcon_unwrap(q_)))
|
|
|
|
|
+static inline struct lqueue_link *lqueue_front_(const struct lqueue_ *q)
|
|
|
{
|
|
{
|
|
|
if (!q->back)
|
|
if (!q->back)
|
|
|
return NULL;
|
|
return NULL;
|
|
@@ -148,20 +171,18 @@ static inline struct lqueue_link *lqueue_front_(const struct lqueue *q)
|
|
|
/**
|
|
/**
|
|
|
* lqueue_back - get back entry in a queue
|
|
* lqueue_back - get back entry in a queue
|
|
|
* @q: the queue
|
|
* @q: the queue
|
|
|
- * @type: the type of queue entries
|
|
|
|
|
- * @member: the lqueue_link entry
|
|
|
|
|
*
|
|
*
|
|
|
* If the queue is empty, returns NULL.
|
|
* If the queue is empty, returns NULL.
|
|
|
*
|
|
*
|
|
|
* Example:
|
|
* Example:
|
|
|
- * struct waiter b;
|
|
|
|
|
|
|
+ * struct element b;
|
|
|
*
|
|
*
|
|
|
- * lqueue_enqueue(qp, &b, ql);
|
|
|
|
|
- * assert(lqueue_back(qp, struct waiter, ql) == &b);
|
|
|
|
|
|
|
+ * lqueue_enqueue(qp, &b);
|
|
|
|
|
+ * assert(lqueue_back(qp) == &b);
|
|
|
*/
|
|
*/
|
|
|
-#define lqueue_back(q, type, member) \
|
|
|
|
|
- lqueue_entry(lqueue_back_((q)), type, member)
|
|
|
|
|
-static inline struct lqueue_link *lqueue_back_(const struct lqueue *q)
|
|
|
|
|
|
|
+#define lqueue_back(q_) \
|
|
|
|
|
+ lqueue_entry((q_), lqueue_back_(tcon_unwrap(q_)))
|
|
|
|
|
+static inline struct lqueue_link *lqueue_back_(const struct lqueue_ *q)
|
|
|
{
|
|
{
|
|
|
return q->back;
|
|
return q->back;
|
|
|
}
|
|
}
|
|
@@ -170,15 +191,14 @@ static inline struct lqueue_link *lqueue_back_(const struct lqueue *q)
|
|
|
* lqueue_enqueue - add an entry to the back of a queue
|
|
* lqueue_enqueue - add an entry to the back of a queue
|
|
|
* @q: the queue to add the node to
|
|
* @q: the queue to add the node to
|
|
|
* @e: the item to enqueue
|
|
* @e: the item to enqueue
|
|
|
- * @member: the lqueue_link field of *e
|
|
|
|
|
*
|
|
*
|
|
|
* The lqueue_link does not need to be initialized; it will be overwritten.
|
|
* The lqueue_link does not need to be initialized; it will be overwritten.
|
|
|
*/
|
|
*/
|
|
|
-#define lqueue_enqueue(q, e, member) \
|
|
|
|
|
- lqueue_enqueue_((q), &((e)->member))
|
|
|
|
|
-static inline void lqueue_enqueue_(struct lqueue *q, struct lqueue_link *e)
|
|
|
|
|
|
|
+#define lqueue_enqueue(q_, e_) \
|
|
|
|
|
+ lqueue_enqueue_(tcon_unwrap(q_), tcon_member_of((q_), canary, (e_)))
|
|
|
|
|
+static inline void lqueue_enqueue_(struct lqueue_ *q, struct lqueue_link *e)
|
|
|
{
|
|
{
|
|
|
- if (lqueue_empty(q)) {
|
|
|
|
|
|
|
+ if (lqueue_empty_(q)) {
|
|
|
/* New entry will be both front and back of queue */
|
|
/* New entry will be both front and back of queue */
|
|
|
e->next = e;
|
|
e->next = e;
|
|
|
q->back = e;
|
|
q->back = e;
|
|
@@ -192,19 +212,17 @@ static inline void lqueue_enqueue_(struct lqueue *q, struct lqueue_link *e)
|
|
|
/**
|
|
/**
|
|
|
* lqueue_dequeue - remove and return the entry from the front of the queue
|
|
* lqueue_dequeue - remove and return the entry from the front of the queue
|
|
|
* @q: the queue
|
|
* @q: the queue
|
|
|
- * @type: the type of queue entries
|
|
|
|
|
- * @member: the lqueue_link field of @type
|
|
|
|
|
*
|
|
*
|
|
|
* Note that this leaves the returned entry's link in an undefined
|
|
* Note that this leaves the returned entry's link in an undefined
|
|
|
* state; it can be added to another queue, but not deleted again.
|
|
* state; it can be added to another queue, but not deleted again.
|
|
|
*/
|
|
*/
|
|
|
-#define lqueue_dequeue(q, type, member) \
|
|
|
|
|
- lqueue_entry(lqueue_dequeue_((q)), type, member)
|
|
|
|
|
-static inline struct lqueue_link *lqueue_dequeue_(struct lqueue *q)
|
|
|
|
|
|
|
+#define lqueue_dequeue(q_) \
|
|
|
|
|
+ lqueue_entry((q_), lqueue_dequeue_(tcon_unwrap(q_)))
|
|
|
|
|
+static inline struct lqueue_link *lqueue_dequeue_(struct lqueue_ *q)
|
|
|
{
|
|
{
|
|
|
struct lqueue_link *front;
|
|
struct lqueue_link *front;
|
|
|
|
|
|
|
|
- if (lqueue_empty(q))
|
|
|
|
|
|
|
+ if (lqueue_empty_(q))
|
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
|
|
front = lqueue_front_(q);
|
|
front = lqueue_front_(q);
|