前言
- 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;
}