【数据结构设计】
#define ADT_DLIST_DEF(s_name) \
struct { \
struct s_name* next; \
struct s_name* prev; \
} DLIST
typedef struct AdtDList_s
{
ADT_DLIST_DEF(AdtDList_s); /**< List head */
} AdtDList_t;
【通用性】ADT_DLIST_DEF设计使得list_head自动适配各种业务数据。
【AdtDList_t】AdtDList_t作为业务数据中的list head。
【接口实现】
#define ADT_DLIST_NEXT(node) ((node)->DLIST.next)
#define ADT_DLIST_PREV(node) ((node)->DLIST.prev)
#define ADT_DLIST_HEAD_INIT(head) \
do { \
ADT_DLIST_NEXT(head) = (head); \
ADT_DLIST_PREV(head) = (head); \
} while(0)
#define ADT_DLIST_NODE_INIT(node) \
do { \
ADT_DLIST_NEXT(node) = NULL; \
ADT_DLIST_PREV(node) = NULL; \
} while(0)
#define ADT_DLIST_LINK_NEXT(link, node) \
do { \
ADT_DLIST_NEXT(node) = ADT_DLIST_NEXT(link); \
ADT_DLIST_PREV(node) = (link); \
ADT_DLIST_NEXT(link) = (node); \
ADT_DLIST_PREV(ADT_DLIST_NEXT(node)) = (node); \
} while(0)
#define ADT_DLIST_LINK_PREV(link, node) \
do { \
ADT_DLIST_PREV(node) = ADT_DLIST_PREV(link); \
ADT_DLIST_NEXT(node) = (link); \
ADT_DLIST_PREV(link) = (node); \
ADT_DLIST_NEXT(ADT_DLIST_PREV(link)) = (node); \
} while(0)
#define ADT_DLIST_UNLINK(link) \
do { \
ADT_DLIST_PREV(ADT_DLIST_NEXT(link)) = ADT_DLIST_PREV(link); \
ADT_DLIST_NEXT(ADT_DLIST_PREV(link)) = ADT_DLIST_NEXT(link); \
ADT_DLIST_NODE_INIT(link); \
} while(0)
#define ADT_DLIST_EACH_NEXT(head, link) \
for (link = head; (link = ADT_DLIST_NEXT(link)) != (head); )
#define ADT_DLIST_EACH_NEXT_SAFE(head, link, save) \
for ((void) (link = ADT_DLIST_NEXT(head)), save = ADT_DLIST_NEXT(link) ; \
link != (head); \
(void) (link = save), (void) (save = ADT_DLIST_NEXT(link)))
define ADT_DLIST_EACH_PREV(head, link) \
for (link = head; (link = ADT_DLIST_PREV(link)) != (head); )
#define ADT_DLIST_EACH_PREV_SAFE(head, link, save) \
for ((void) (link = ADT_DLIST_PREV(head)), save = ADT_DLIST_PREV(link) ; \
link != (head); \
(void) (link = save), (void) (save = ADT_DLIST_PREV(link)))
#define ADT_DLIST_IS_EMPTY(head) (ADT_DLIST_NEXT(head) == head)
#define ADT_DLIST_IS_LINKED(node) (ADT_DLIST_NEXT(node) != NULL)
【ADT_DLIST_LINK_NEXT】先处理新节点作为缓冲是比较明智又安全的做法。PREV操作是把所有NEXT和PREV对调。
【ADT_DLIST_EACH_NEXT】不可用在含删除节点操作的场景中。有删除节点操作,须使用:ADT_DLIST_EACH_NEXT_SAFE。安全的原因是tmp保存了被删除节点的元数据信息,可以使得循环链不会被断掉。
【测试用例】
typedef struct node_d_ {
AdtDList_t dlink;
int val;
} node_d;
int test_dlist()
{
int i = 0;
node_d *item = NULL;
AdtDList_t dlist;
AdtDList_t *dlink = NULL;
ADT_DLIST_HEAD_INIT(&dlist); ///INIT
for (i=0; i<10; i++) {
item = (node_d *) malloc(sizeof(node_d));
if (item) {
memset(item, 0x0, sizeof(node_d));
item->val = i;
ADT_DLIST_NODE_INIT(&item->dlink); ///INIT_NODE
ADT_DLIST_LINK_PREV(&dlist, &item->dlink); /// LINK
}
item = NULL;
}
ADT_DLIST_EACH_PREV(&dlist, dlink) { //LOOP
node_d *node = container_of(dlink, node_d, dlink);
printf("%d ", node->val);
}
printf("\n");
//free TODO
return 0;
}