对照前面介绍过的内核通知链、链表,本章我们将要介绍的哈希表的初始化和定义也是如出一辙的:
其中,HLIST_HEAD_INIT 一般这么用:
对于哈希表中的每一个hlist_node节点,通常情况下都要调用初始化函数INIT_HLIST_NODE()来初始化:
一个给定的哈希节点,判断它是否已经被插入到某条哈希链表里hlist_unhashed():
这里我们可以看到,
hlist_node
里的
pprev
完成了这个功能,即如果一个
hlist_node
的
pprev
为
NULL
,则说明该节点目前并未加入任何哈希链表。
下面这个接口就没啥好说的,用于判断是一个给定哈希表是否为空(即不包含任何哈希节点)。注意,该接口入参为 hlist_head 类型而非 hlist_node 类型:
剩下的其他接口,也都非常简单,这里不再一一赘述。下面我们看几个宏定义:
对照list的学习过程,可想而知,下面这几组结构,其作用也就不言而喻了:
区别在于最后两个宏的入参上有些小区别。由于哈希链表,表头和表节点是不同的数据结构,所以才会有这个差异。还是对照着list_for_each_*的学习过程:
其中tpos,是hlist_node所属宿主结构体类型的指针,pos是hlist_node类型的指针,tpos和pos都充当的游标的作用。例如:
同样地,在使用hlist_for_each_entry_safe(tpos, pos, n, head, member)时,tpos也是宿主结构体类型的一个指针变量,当游标使用,n是一个hlist_node类型的另一个指针,这个指针指向pos所在元素的下一个元素,它由hlist_for_each_entry_safe()本身进行维护,开发者不用修改它:
点击(此处)折叠或打开
- 定义并初始化一个名为name的哈希链表表头
- #define HLIST_HEAD(name) struct hlist_head name = {
.first = NULL }
-
- 初始化一个已经定义好的哈希链表,其中ptr指向哈希表头的地址
- #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
其中,HLIST_HEAD_INIT 一般这么用:
点击(此处)折叠或打开
- struct hlist_head myhlist;
- HLIST_HEAD_INIT(&myhlist);
对于哈希表中的每一个hlist_node节点,通常情况下都要调用初始化函数INIT_HLIST_NODE()来初始化:
点击(此处)折叠或打开
- static inline void INIT_HLIST_NODE(struct hlist_node *h)
- {
- h->next = NULL;
- h->pprev = NULL;
- }
一个给定的哈希节点,判断它是否已经被插入到某条哈希链表里hlist_unhashed():
点击(此处)折叠或打开
- static inline int hlist_unhashed(const struct hlist_node *h)
- {
- return !h->pprev;
- }
下面这个接口就没啥好说的,用于判断是一个给定哈希表是否为空(即不包含任何哈希节点)。注意,该接口入参为 hlist_head 类型而非 hlist_node 类型:
点击(此处)折叠或打开
- static inline int hlist_empty(const struct hlist_head *h)
- {
- return !h->first;
- }
剩下的其他接口,也都非常简单,这里不再一一赘述。下面我们看几个宏定义:
点击(此处)折叠或打开
- #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
- 该宏和前面介绍过的list_entry()的实现、作用完全一样
- #define list_entry(ptr, type, member) container_of(ptr,type,member)
对照list的学习过程,可想而知,下面这几组结构,其作用也就不言而喻了:
哈希表 | 链表 |
hlist_for_each(pos, head) |
list_for_each(pos, head) |
hlist_for_each_safe(pos, n, head) |
list_for_each_safe(pos, n, head) |
hlist_for_each_entry(tpos, pos, head, member) |
list_for_each_entry(pos, head, member) |
hlist_for_each_entry_safe(tpos, pos, n, head, member) |
list_for_each_entry_safe(pos, n, head, member) |
区别在于最后两个宏的入参上有些小区别。由于哈希链表,表头和表节点是不同的数据结构,所以才会有这个差异。还是对照着list_for_each_*的学习过程:
点击(此处)折叠或打开
- hlist_for_each_entry(tpos, pos, head, member)
点击(此处)折叠或打开
- typedef struct student
- {
- char m_name[MAX_STRING_LEN];
- char m_sex;
- int m_age;
- struct list_head m_list; /*把我们的学生对象组织成双向链表,就靠该节点了*/
- struct hlist_node m_hlist; /*把我们的学生对象组织成哈希链表,就靠该节点了*/
- }Student;
-
- HLIST_HEAD(myhlist);
- Student *st;
- struct hlist_node *i;
- hlist_for_each_entry(st, i, &myhlist, m_hlist)
- {
- //To do something here…
- //通常情况,开发者在这里仅需要关注、使用st变量就可以,不需要关心i
- }
同样地,在使用hlist_for_each_entry_safe(tpos, pos, n, head, member)时,tpos也是宿主结构体类型的一个指针变量,当游标使用,n是一个hlist_node类型的另一个指针,这个指针指向pos所在元素的下一个元素,它由hlist_for_each_entry_safe()本身进行维护,开发者不用修改它:
点击(此处)折叠或打开
- HLIST_HEAD(myhlist);
- Student *st;
- struct hlist_node *i,*j;