前言
- 20201010
- 在阅读 RTOS LiteOS 内核源码时发现该内核使用的链表时通用链表,而 FreeRTOS 内核使用的时非通用链表,所以,有必要发布一下关于链表实现的笔记。
- 以下内容为个人笔记,涉及一些非专业词汇,敬请谅解,谢谢。
链接
参考
头文件 lssList.h
/**
******************************************************************************
* @file comList.h
* @author lzm
* @version V1.0
* @date 2020-09-26
* @brief 参考FreeRTOS
* @attention
*
* 实验平台:LZM
*
******************************************************************************
*/
#ifndef _LSS_LIST_H_
#define _LSS_LIST_H_
#include "LssAppConfig.h"
/*
*********************************************************************************************************
* CONFIG
*********************************************************************************************************
*/
#define lssLIST_MAX_VALUE 0XFFFFFFFF
#define lssLIST_BASE_TYPE unsigned long
/*
*********************************************************************************************************
* STRUCT
*********************************************************************************************************
*/
/*
* The linked list node
*/
struct LIST_ITEM_LSS_T
{
uint32_t xItemValue; // 记号值
struct LIST_ITEM_LSS_T * pxNext; // 上一个
struct LIST_ITEM_LSS_T * pxPrevious; // 下一个
void * pvOwner; // 挂钩
void * pvContainer; // 归属
};
typedef struct LIST_ITEM_LSS_T listItem_t;
/*
* Linked list mini node
*/
struct LIST_MINI_ITEM_LSS_T
{
uint32_t xItemValue; // 记号值(跟节点,一般为最大)
struct LIST_ITEM_LSS_T * pxNext;
struct LIST_ITEM_LSS_T * pxPrevious;
};
typedef struct LIST_MINI_ITEM_LSS_T listMiniItem_t;
/*
* The linked list (or root node)
*/
struct LIST_LSS_T
{
uint32_t uxNumberOfItems; // 节点总数(忽略根节点)
struct LIST_ITEM_LSS_T * pxIndex; // 链表索引
struct LIST_MINI_ITEM_LSS_T xListEnd; // 链表根节点
};
typedef struct LIST_LSS_T list_t;
/*
*********************************************************************************************************
* FUNCTION
*********************************************************************************************************
*/
void listInit(list_t * const list);
void listItemInit(listItem_t * const item);
void listInsertEnd( list_t * const pxList, listItem_t * const pxNewListItem );
void listInsert( list_t * const pxList, listItem_t * const pxNewListItem );
uint32_t listRemove( listItem_t * const pxItemToRemove );
/*
*********************************************************************************************************
* API
*********************************************************************************************************
*/
/* 配对挂钩与袜子 */
#define lssSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) \
( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/* 获取袜子 */
#define lssGET_LIST_ITEM_OWNER( pxListItem ) \
( ( pxListItem )->pvOwner )
/* 设置记号值 */
#define lssSET_LIST_ITEM_VALUE( pxListItem, xValue ) \
( ( pxListItem )->xItemValue = ( xValue ) )
/* 获取记号值 */
#define lssGET_LIST_ITEM_VALUE( pxListItem ) \
( ( pxListItem )->xItemValue )
/* 获取第一个节点的节点值(*第一个节点和根节点是两回事*)*/
#define lssGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) \
( ( ( pxList )->xListEnd ).pxNext->xItemValue )
/* 获取链表的入口节点 */
#define lssGET_HEAD_ENTRY( pxList ) \
( ( ( pxList )->xListEnd ).pxNext )
/* 获取下一个节点 */
#define lssGET_NEXT( pxListItem ) \
( ( pxListItem )->pxNext )
/* 获取链表最后一个节点:头节点 */
#define lssGET_END_MARKER( pxList ) \
( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
/* 判断链表是否为空 */
#define lssLIST_IS_EMPTY( pxList ) \
( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) )
/* 获取链表当前节点总数 */
#define lssCURRENT_LIST_LENGTH( pxList ) \
( ( pxList )->uxNumberOfItems )
/* 获取链表索引指向的下一个挂钩 */
#define lssGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
{ \
list_t * const pxConstList = ( pxList ); \ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
{ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
} \
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;\
} \
}
#endif
源文件 lssList.c
/**
******************************************************************************
* @file lssList.c
* @author lzm
* @version V1.0
* @date 2020-09-26
* @brief 参考FreeRTOS
* 双链表
* @attention
*
* 实验平台:LZM
*
******************************************************************************
*/
#include "lssList.h"
/**
* @brief 链表初始化
* @param
* @retval
* @author lzm
*/
void listInit(list_t * const list)
{
/* 索引指向最后:尾就是头 */
list->pxIndex = (listItem_t *) &(list->xListEnd);
/* 链表最大值 */
list->xListEnd.xItemValue = lssLIST_MAX_VALUE;
list->xListEnd.pxNext = ( listItem_t * ) &( list->xListEnd );
list->xListEnd.pxPrevious = ( listItem_t * ) &( list->xListEnd );
list->uxNumberOfItems = (lssLIST_BASE_TYPE)0U;
}
/**
* @brief 节点初始化
* @param
* @retval
* @author lzm
*/
void listItemInit(listItem_t * const item)
{
item->pvContainer = NULL;
}
/**
* @brief 插入链表尾部(*双向链表没有绝对的头尾,此处是以游标为参考物*)
* @param
* @retval
* @author lzm
*/
void listInsertEnd( list_t * const pxList, listItem_t * const pxNewListItem )
{
listItem_t * const pxIndex = pxList->pxIndex;
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/* Remember which list the item is in. */
pxNewListItem->pvContainer = ( void * ) pxList;
( pxList->uxNumberOfItems )++;
}
/**
* @brief 按记号值值插入
* @param
* @retval
* @author lzm
*/
void listInsert( list_t * const pxList, listItem_t * const pxNewListItem )
{
listItem_t *pxIterator;
const lssLIST_BASE_TYPE xValueOfInsertion = pxNewListItem->xItemValue; // 获取新节点记号值
/* 按顺序寻找 */
if( xValueOfInsertion == lssLIST_MAX_VALUE )
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
for( pxIterator = ( listItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
{
/* There is nothing to do here, just iterating to the wanted
insertion position. */
}
}
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
/* Remember which list the item is in. This allows fast removal of the
item later. */
pxNewListItem->pvContainer = ( void * ) pxList;
( pxList->uxNumberOfItems )++;
}
/**
* @brief 从链表中删除节点
* @param
* @retval
* @author lzm
*/
uint32_t listRemove( listItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in. Obtain the list from the list
item. */
list_t * const pxList = ( list_t * ) pxItemToRemove->pvContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/* Make sure the index is left pointing to a valid item. */
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
pxItemToRemove->pvContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
}