Libevent: 在C语言中实现泛型数据结构

拿最简单的单链表来说说,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)

以上操作均不涉及元素的内存释放,因而内存的管理权在用户手中。

参考: Libevent 基础数据结构 链表分析

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值