鏈表-雙向非通用鏈表-源碼


前言

  • 20201010
  • 在閱讀 RTOS LiteOS 內核源碼時發現該內核使用的鏈表時通用鏈表,而 FreeRTOS 內核使用的時非通用鏈表,因此,有必要發佈一下關於鏈表實現的筆記。
  • 如下內容爲我的筆記,涉及一些非專業詞彙,敬請諒解,謝謝。

連接

參考

  • 上面連接
  • 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;
}
相關文章
相關標籤/搜索