zephyr單向鏈表
zephyr鏈表使用靜態內聯函數, 只有 .h 文件, 沒有對應的 .c 文件.
slist.h 位於 /${ZEPHYR_BASE}/include/misc/slist.h
鏈表定義
#節點定義, 此處添加節點的數據
struct _snode {
struct _snode *next;
};
#鏈表定義, 鏈表頭、尾指針
struct _slist {
sys_snode_t *head;
sys_snode_t *tail;
};
#重定義節點類型, 兼容之前的定義
typedef struct _snode sys_snode_t;
typedef struct _slist sys_slist_t;
常用鏈表函數
- 初始化鏈表
# 將頭尾指針置爲空
static inline void sys_slist_init(sys_slist_t *list)
{
list->head = NULL;
list->tail = NULL;
}
- 判斷鏈表是否爲空
#True: 鏈表爲空, False: 鏈表不爲空
static inline bool sys_slist_is_empty(sys_slist_t *list)
{
return (!list->head);
}
- 返回鏈表頭/尾節點
#返回頭結點的指針
static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list)
{
return list->head;
}
#返回尾結點的指針
static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list)
{
return list->tail;
}
- 返回當前節點的下一個節點
#Note: 此函數速度快, 如不確定函數是否爲空,則使用 sys_slist_peek_next()函數
static inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node)
{
return node->next;
}
#函數會檢測鏈表是否爲空
static inline sys_snode_t *sys_slist_peek_next(sys_node_t * node)
{
return node ? sys_slist_peek_next_no_check(node) : NULL;
}
- 添加節點到鏈表頭/尾
#表頭前插節點
static inline void sys_slist_prepend(sys_slist_t *list, sys_snode_t *node)
{
node->next = list->head; #將該節點的next域指向鏈表頭
list->head = node; #將該節點設置爲頭結點
if (!list->tail) #鏈表爲空, 則需要將尾重新指向新表頭
{
list->tail = list->head; #表尾指向新表頭
}
}
#表尾後插節點
static inline void sys_slist_append(sys_slist_t *list, sys_snode_t *node)
{
node->next = null; #該節點添加於鏈表尾, 則它後面沒有節點, 需要置空
if (!list->tail) #鏈表爲空, 則需將首尾節點均指向該節點
{
list->tail = node;
list->head = node;
}
else #鏈表不爲空, 則將鏈表尾指向的下一個節點指向該節點, 同時將鏈表尾指針指向該節點
{
list->tail->next = node;
list->tail = node;
}
}
- 在原鏈表尾部添加鏈表/合併鏈表
#原鏈表後插鏈表
static inline void sys_slist_append_list(sys_slist_t *list, void *head, void *tail)
{
if (!list->tail) #鏈表爲空, 則直接將首尾指針賦值爲新加鏈表
{
list->head = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
else #鏈表不爲空, 則將其頭添加到原鏈表尾, 同時將原鏈表尾指向新加鏈表尾
{
list->tail->next = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
}
#合併鏈表, 後插鏈表後, 再將其清空
static inline void sys_slist_merge_slist(sys_slist_t *list, sys_slist_t *list_to_append)
{
sys_slist_append_list(list, list_to_append->head, list_to_append->tail);
sys_slist_init(list_to_append);
}
- 指定節點後插入節點
static inline void sys_slist_insert(sys_slist_t *list, sys_snode_t *prev, sys_snode_t *node)
{
if (!prev) #指定節點爲頭節點 則添加到鏈表頭
{
sys_slist_prepend(list, node);
}
else if (!prev->next) #指定節點爲尾節點, 則添加到鏈表尾
{
sys_slist_append(list, node);
}
else #添加到指定節點後
{
node->next = prev->next;
prev->next = node;
}
}
- 移除頭節點(鏈表頭)
#Note: 調用該函數時, 必須確保鏈表不爲空
static inline sys_snode_t *sys_slist_not_empty(sys_slist_t *list)
{
sys_snode_t *node = list->head; #保存鏈表頭
list->head = node->next; #將原鏈表頭的地址復爲新鏈表頭
if (list->tail == node) #鏈表只有一個節點, 去掉之後需要更新鏈表尾
{
list->tail = list->head;
}
return node; #返回頭節點指針
}
#移除頭結點, 空鏈表將會返回NULL
static inline sys_snode_t *sys_slist_get(sys_slist_t *list)
{
return sys_slist_empty(list) ? NULL : sys_slist_get_not_empty(list);
}
- 移除指定節點的後一個節點
static inline void sys_slist_remove(sys_slist_t *list, sys_snode_t *prev_node, sys_snode_t *node)
{
if (!prev_node) #指定節點爲空, 即刪除頭節點, 將刪除節點的下一個節點置爲頭結點
{
list->head = node->next;
if (list->tail == node) #鏈表只有一個節點, 刪除該節點前, 需要將尾指針指向頭指針
{
list->tail = list->head;
}
}
else #指定節點不爲空, 將指定節點的下一個節點指向刪除節點的下一個節點
{
prev_node->next = node->next;
if (list->tail == node) #刪除節點爲尾節點, 則將尾指針指向賦值爲指定節點
{
list->tail = prev_node;
}
}
node->next = NULL;
}
- 從鏈表找到並移除一個節點
#刪除節點存在, 刪除並返回True, 未找到則返回False
static inline bool sys_slist_find_and_remove(sys_slist_t *list, sys_snode_t *node)
{
sys_snode_t *prev = NULL;
sys_snode_t *test;
SYS_SLIST_FOR_EACH_NODE(list, test) #宏定義,用於遍歷列表
if (test == node) #找到要刪除的節點, 調用方法刪除, 並返回True
{
sys_slist_remove(list, prev, node);
return true;
}
prev = test; #循環條件, 依次往後遍歷鏈表
}
return false; #未找到刪除節點, 返回False
}
#遍歷列表宏定義 <使用方法如上所示>
#defiune SYS_SLIST_FOR_EACH_NODE(__s1, __sn) \
for (__sn = sys_slist_peek_head(__s1); __sn; __sn = sys_slist_peek_next(__sn))