/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
TAILQ_ENTRY沒有結構體名,所以它一般都是另外一個結構體的成員,tqe_next和tqh_frist是一級指向結構體地址,tqh_last和tqh_prev是二級指針,也就是指向指針的指針,所以指向隊列的next指針,構造出來的隊列一般如下圖所示:
隊列操作宏函數如下:
//隊列中的第一個元素
#define TAILQ_FIRST(head) ((head)->tqh_first)
//隊列結束
#define TAILQ_END(head) NULL
//隊列中當前元素的下一個節點
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
//隊列最後一個節點
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
//隊列前一個節點
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
//隊列是否爲空
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
//隊列遍歷
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
//隊列從尾遍歷
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
/*
* Tail queue functions.
*/
//隊列頭初始化
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
//隊列初始化
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
//隊列頭插入節點
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
//隊列尾插入節點
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
//隊列節點後插入
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
//隊列節點前插入
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
//隊列節點刪除
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
} while (0)
//替換隊列節點
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
} while (0)
其他的宏都比較簡單,比較好理解,TAILQ_LAST,TAILQ_PREV這兩個宏可能比較難理解。
//隊列最後一個元素
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
一級指針tqh_first指向隊列第一個節點的地址,二級指針tqh_last指向隊列最後一個節點的next指針,隊列節點的TAILQ_ENTRY同樣也是一級指針tqe_next指向下一個節點的地址,tqe_prev指向前一個節點的next指針。
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
下面這張圖更能反映文中結構體的內存佈局,TAILQ_HEAD和TAILQ_ENTRY都是一級指針在前二級指針在後,TAILQ_HEAD和TAILQ__ENTRY內存分佈相同,強制類型轉換獲取TAILQ_ENTRY的地址,因爲**tqh_last指向*tqh_next, 無論一級還是二級指針,其都是指向另外一個地址,二級指針指向一級指針的地址,TAILQ_ENTRY結構中tqh_next在前它的地址強制類型轉換TAILQ_HEAD,前面說的TAILQ_HEAD和TAIL_ENTRY內存結構相同,就可以表示TAILQ_ENTRY的地址,全部通過指針獲取元素的值。
TAILQ_HEAD (event_list, event);
//所以event_list的定義展開後如下:
struct event_list
{
struct event *tqh_first;
struct event **tqh_last;
};
struct event_base;
struct event {
struct event_callback ev_evcallback;
/* for managing timeouts */
union {
TAILQ_ENTRY(event) ev_next_with_common_timeout;
size_t min_heap_idx;
} ev_timeout_pos;
evutil_socket_t ev_fd;
struct event_base *ev_base;
union {
/* used for io events */
struct {
LIST_ENTRY (event) ev_io_next;
struct timeval ev_timeout;
} ev_io;
/* used by signal events */
struct {
LIST_ENTRY (event) ev_signal_next;
short ev_ncalls;
/* Allows deletes in callback */
short *ev_pncalls;
} ev_signal;
} ev_;
short ev_events;
short ev_res; /* result passed to event callback */
struct timeval ev_timeout;
};
TAILQ_HEAD (event_list, event);
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
#define ENTRY_NAME entry
struct queue_entry_t
{
int value;
//從TAILQ_ENTRY的定義可知,它只能是結構體或者共用體的成員變量
TAILQ_ENTRY(queue_entry_t)ENTRY_NAME;
};
TAILQ_HEAD(queue_head_t, queue_entry_t);
int main(int argc, char **argv)
{
struct queue_head_t queue_head;
struct queue_entry_t *queue, *new_item, *tmp,*next;
int i;
int var ;
TAILQ_INIT(&queue_head);
for(i = 0; i < 6; ++i)
{
new_item = NULL ;
new_item = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
new_item->value = i;
TAILQ_INSERT_TAIL(&queue_head, new_item, ENTRY_NAME);//在隊尾插入數據
}
queue = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
queue->value = 10;
TAILQ_INSERT_HEAD(&queue_head, queue, ENTRY_NAME);//在隊頭插入數據
tmp = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
tmp->value = 20;
//在隊頭元素q的後面插入元素
TAILQ_INSERT_AFTER(&queue_head, queue, tmp, ENTRY_NAME);
i = 0 ;
TAILQ_FOREACH(tmp, &queue_head, ENTRY_NAME)
{
i++ ;
printf("the %dth entry is %d\n", i,tmp->value) ;
}
new_item = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
new_item->value = 100;
tmp = TAILQ_FIRST(&queue_head);
//用new_iten替換第一個元素
TAILQ_REPLACE(&queue_head, tmp, new_item, ENTRY_NAME);
free(tmp) ;
i = 0 ;
TAILQ_FOREACH(tmp, &queue_head, ENTRY_NAME)
{
i++ ;
printf("the %dth entry is %d\n", i,tmp->value) ;
}
while ( (tmp) = TAILQ_FIRST(&queue_head) ) {
TAILQ_REMOVE(&queue_head, tmp, ENTRY_NAME);
free(tmp);
}
if (!TAILQ_EMPTY(&queue_head)) {
printf("tail queue is NOT empty!\n");
}
return 0 ;
}