# jh_static_list **Repository Path**: arrco/jh_static_list ## Basic Information - **Project Name**: jh_static_list - **Description**: jh_static_list是一个静态双向链表。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-02-20 - **Last Updated**: 2023-02-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # jh_static_list ## 介绍 jh_static_list是一个静态双向链表。适用于在资源紧张的MCU上替代动态链表使用,可以节省一些RAM空间开销。动态双向链表的前向指针和后向指针在32位的设备上固定就会占用8Byte的空间,而使用静态双向链表,在链表长度小于255的情况下,只需要使用2Byte的空间,在链表长度小于65535的情况下,只需要使用4Byte的空间,可以极大减少内存开销。 jh_static_list设计时参考了Linux和Harmony LiteOS的链表风格。 ## 使用说明 只需要包含`jh_static_list.h`一个文件即可使用。 ## 接口函数 提供以下接口用于静态链表的使用,每个接口的说明详见`jh_static_list.h`中的接口注释: ```c /*链表缓冲区初始化*/ static inline void jh_static_list_buf_init(jh_static_list_buf list); /*链表初始化*/ static inline void jh_static_list_init(jh_static_list_buf list, uint32_t cursor); /*申请链表游标*/ static inline uint32_t jh_static_list_malloc(jh_static_list_buf list); /*释放链表游标*/ static inline void jh_static_list_free(jh_static_list_buf list, uint32_t cursor); /*链表是否为空*/ static inline uint32_t jh_static_list_is_empty(jh_static_list_buf list); /*链表是否已满*/ static inline uint32_t jh_static_list_is_full(jh_static_list_buf list); /*向链表中添加结点*/ static inline void jh_static_list_add(jh_static_list_buf list, uint32_t target, uint32_t cursor); /*向链表头添加结点*/ static inline void jh_static_list_head_insert(jh_static_list_buf list, uint32_t cursor); /*向链表尾添加结点*/ static inline void jh_static_list_tail_insert(jh_static_list_buf list, uint32_t cursor); /*从链表中删除结点*/ static inline void jh_static_list_delete(jh_static_list_buf list, uint32_t cursor); /*从链表中删除并释放结点*/ static inline void jh_static_list_delete_and_free(jh_static_list_buf list, uint32_t cursor); /*从链表中删除并释放头结点*/ static inline void jh_static_list_remove_head(jh_static_list_buf list); /*从链表中删除并释放尾结点*/ static inline void jh_static_list_remove_tail(jh_static_list_buf list); /*从链表中删除并返回头结点的游标*/ static inline uint32_t jh_static_list_get_and_remove_head_cursor(jh_static_list_buf list); /*从链表中删除并返回尾结点的游标*/ static inline uint32_t jh_static_list_get_and_remove_tail_cursor(jh_static_list_buf list); /*链表游标是否有效*/ static inline uint32_t jh_static_list_cursor_is_vaild(uint32_t cursor); ``` 同时提供大量的宏接口以便于使用链表,每个接口的说明详见`jh_static_list.h`中的接口注释,使用方式可以参考`example`目录下的测试程序: ```c /*遍历链表*/ JH_STATIC_LIST_FOR_EACH(item, list) /*安全的遍历链表,可以在遍历中删除结点*/ JH_STATIC_LIST_FOR_EACH_SAFE(item, nextitem, list) /*反向遍历链表*/ JH_STATIC_LIST_FOR_EACH_REVERSE(item, list) /*安全的反向遍历链表,可以在遍历中删除结点*/ JH_STATIC_LIST_FOR_EACH_SAFE_REVERSE(item, previtem, list) /*遍历链表获取数据*/ JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT(item, list, member, element) /*反向遍历链表获取数据*/ JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT_REVERSE(item, list, member, element) /*安全的遍历链表获取数据,可以在遍历中删除结点*/ JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT_SAFE(item, nextitem, list, member, element) /*安全的反向遍历链表获取数据,可以在遍历中删除结点*/ JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT_SAFE_REVERSE(item, previtem, list, member, element) /*查看链表头的数据*/ JH_STATIC_LIST_PEEK_HEAD_TYPE(list, type, element) /*查看链表尾的数据*/ JH_STATIC_LIST_PEEK_TAIL_TYPE(list, type, element) /*获取链表头的数据,并删除释放结点*/ JH_STATIC_LIST_REMOVE_HEAD_TYPE(list, type, element) /*获取链表尾的数据,并删除结点*/ JH_STATIC_LIST_REMOVE_TAIL_TYPE(list, type, element) /*获取链表头的数据,并删除结点*/ JH_STATIC_LIST_REMOVE_HEAD_TYPE_SAFE(list, element, data) /*获取链表尾的数据,并删除结点*/ JH_STATIC_LIST_REMOVE_TAIL_TYPE_SAFE(list, element, data) /*将数据添加到链表头中,自动申请*/ JH_STATIC_LIST_ADD_HEAD_TYPE(list, element, data) /*将数据添加到链表尾中,自动申请*/ JH_STATIC_LIST_ADD_TAIL_TYPE(list, element, data) /*将数据添加到链表中,自动申请*/ JH_STATIC_LIST_ADD_TARGET_TYPE(list, target, element, data) ``` 以上的宏接口基本涵盖了链表所有的基础操作。 ## 链表使用说明 ### 1.链表配置 在使用链表前,需要在`jh_static_list.h`中进行一些配置。 首先是需要支持uint8_t,uint16_t,uint32_t这几个类型。 默认定义如下,需要根据实际使用的环境进行定义: ```c //使用前需要支持这些类型 typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; ``` 其次是定义静态链表的可用数据数组长度`JH_STATIC_LIST_BUF_VALID_LEN`,链表数据的数据类型和名称。 例如默认数据的数据结构是uint32_t,数据长度62,数据成员名称为data。 ```c //使用前需要设置以下参数 //存储空间有多大 #define JH_STATIC_LIST_BUF_VALID_LEN 62 //使用的数据类型 typedef uint32_t itemtype; //使用的数据成员名称 #define JH_ITEM_NAME data ``` ### 2.链表初始化 使用链表前,要先定义链表,然后进行初始化。例如: ```c //定义链表 jh_static_list_buf list_buf; //初始化 jh_static_list_buf_init(list_buf); ``` ### 3.链表使用示例 往链表里添加数据,遍历查看数据,最后删除链表数据。 ```c int main(int argc, char* argv[]) { int i; int cursor; itemtype value; itemtype *p_value; //定义链表 jh_static_list_buf list_buf; //初始化 jh_static_list_buf_init(list_buf); //放入数据 for (i = 0; i < 10; i++) { value = i + 10; //往链表队尾添加数据 JH_STATIC_LIST_ADD_TAIL_TYPE(list_buf, data, value); printf("Node %d add %d\n", i, value); } printf("\n"); //遍历数据 i = 0; JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT(cursor, list_buf, p_value, data) { printf("Node %d's data: %d\n", i, *p_value); i++; } printf("\n"); //删除数据 for (i = 0; i < 10; i++) { //往链表队尾删除数据 JH_STATIC_LIST_REMOVE_TAIL_TYPE(list_buf, itemtype, data); printf("Node %d has del to the list...\n", i); } printf("\n"); //判断链表是否为空 printf("list %s empty\n", jh_static_list_is_empty(list_buf) ? "is" : "isn't"); printf("\n"); return 0; } ``` 运行结果如下: ``` Node 0 add 10 Node 1 add 11 Node 2 add 12 Node 3 add 13 Node 4 add 14 Node 5 add 15 Node 6 add 16 Node 7 add 17 Node 8 add 18 Node 9 add 19 Node 0's data: 10 Node 1's data: 11 Node 2's data: 12 Node 3's data: 13 Node 4's data: 14 Node 5's data: 15 Node 6's data: 16 Node 7's data: 17 Node 8's data: 18 Node 9's data: 19 Node 0 has del to the list... Node 1 has del to the list... Node 2 has del to the list... Node 3 has del to the list... Node 4 has del to the list... Node 5 has del to the list... Node 6 has del to the list... Node 7 has del to the list... Node 8 has del to the list... Node 9 has del to the list... list is empty ``` 更多的使用方式可以参考example目录下的测试程序,测试程序中提供了遍历链表,反向遍历链表,往链表头和尾添加与删除数据,遍历链表中添加或删除特定数据,移动链表中数据位置等等各种链表基础操作的示例。 ## 其他说明 ### 1.字节对齐 如果需要节约RAM空间,可以使用单字节对齐。需要自行在头文件中的`jh_static_list_buf`结构体中添加,例如: ```c #pragma pack(1) typedef struct { itemtype JH_ITEM_NAME; JH_CURSOR_TYPE prev; JH_CURSOR_TYPE next; } jh_static_list_buf[JH_STATIC_LIST_BUF_LEN]; #pragma pack() ``` 或者 ```c typedef struct { itemtype JH_ITEM_NAME; JH_CURSOR_TYPE prev; JH_CURSOR_TYPE next; } __attribute__((packed)) jh_static_list_buf[JH_STATIC_LIST_BUF_LEN]; ``` 具体实现方式可以根据编译器的情况实现。 ### 2.数据成员 默认只有一个自定义的类型与名称的数据成员,如果需要更多的成员,可以自行在头文件中的`jh_static_list_buf`结构体中添加,例如添加一个`int testval;`。 ```c typedef struct { itemtype JH_ITEM_NAME; int testval; JH_CURSOR_TYPE prev; JH_CURSOR_TYPE next; } jh_static_list_buf[JH_STATIC_LIST_BUF_LEN]; ``` 但是不推荐使用该方式,多个成员应该使用结构体来实现。 ## License MIT License Copyright (c) 2022 Hong Jiahua Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.