拿最简单的单链表来说说,libevent是如何实现泛型数据结构的。
概述
定义\声明: SLIST_HEAD、SLIST_ENTRY
访问接口:
- SLIST_FIRST 获取头节点
- SLIST_END 获取链表尾,实际上就是NULL
- SLIST_EMPTY 判断链表是否为空
- SLIST_FOREACH 遍历链表
- SLIST_NEXT 获取下一个节点
操作接口:
- SLIST_INIT 初始化链表,即头节点置NULL
- SLIST_INSERT_AFTER 在某个节点后插入一个新元素
- SLIST_INSERT_HEAD 头插法
- SLIST_REMOVE_HEAD 删除首元节点
涉及链表的操作,其参数均为指针类型
从Demo中的用法就可以窥探出通过宏实现的泛型。
不同于C++的模板,它要求每个链表节点结构体必须提供一个指针域用来作为接入到链表的入口SLIST_ENTRY
,并通过SLIST_HEAD
在编译期生成相应的链表头节点类型。其余操作与一般的链表操作无异。
Demo:
// 元素的类型
struct Node {
SLIST_ENTRY(Node) next; // 包装next域 为 链表节点
int value; // 其他数据域... ...
};
int main()
{
// 包装生成一个类型为LinkList,元素类型为Node的链表头节点
SLIST_HEAD(LinkList, Node) head;
// 初始化头节点 head->slh_first = NULL
SLIST_INIT(&head);
struct Node* node1 = (struct Node*)malloc(sizeof(struct Node));
node1->value = 1;
struct Node* node2 = (struct Node*)malloc(sizeof(struct Node));
node2->value = 2;
struct Node* node3 = (struct Node*)malloc(sizeof(struct Node));
node3->value = 3;
// 在头结点后面插入 node1
SLIST_INSERT_HEAD(&head, node1, next); // head --> node1 --> NULL
// 在 node1 后面插入 node2
SLIST_INSERT_AFTER(node1, node2, next); // head --> node1 --> node2 --> NULL
// 在 node1 后面插入 node3
SLIST_INSERT_AFTER(node1, node3, next); // head --> node1 --> node3 --> node2 --> NULL
// 删除首元节点 node1
SLIST_REMOVE_HEAD(&head, next); // head --> node3 --> node2 --> NULL
struct Node* temp;
// 遍历链表
SLIST_FOREACH(temp, &head, next)
{
printf("value: %d\n", temp->value);
}
// 销毁链表
while (!SLIST_EMPTY(&head)) {
struct Node* del = SLIST_FIRST(&head);
SLIST_REMOVE_HEAD(&head, next);
free(del);
}
// 遍历链表
SLIST_FOREACH(temp, &head, next)
{
printf("value: %d\n", temp->value);
}
return 0;
}
源码
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#ifndef WIN32
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
#endif
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
以上操作均不涉及元素的内存释放,因而内存的管理权在用户手中。