2019-11-21 03:24:35 +08:00
|
|
|
/*
|
2019-11-21 03:38:08 +08:00
|
|
|
* Amazon FreeRTOS Common V1.0.0
|
|
|
|
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2019-11-21 03:24:35 +08:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* http://aws.amazon.com/freertos
|
|
|
|
* http://www.FreeRTOS.org
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2019-11-21 03:38:08 +08:00
|
|
|
* @file iot_doubly_linked_list.h
|
2019-11-21 03:24:35 +08:00
|
|
|
* @brief Doubly Linked List implementation.
|
|
|
|
*
|
|
|
|
* A generic implementation of circular Doubly Linked List which consists of a
|
|
|
|
* list head and some list entries (zero in case of an empty list).
|
|
|
|
*
|
|
|
|
* To start with, a structure of type Link_t should be embedded in the structure
|
|
|
|
* which is to be organized as doubly linked list.
|
|
|
|
* @code
|
|
|
|
* typedef struct UserStruct
|
|
|
|
* {
|
|
|
|
* uint32_t ulField1;
|
|
|
|
* uint32_t ulField2;
|
|
|
|
* Link_t xLink;
|
|
|
|
* } UserStruct_t;
|
|
|
|
* @endcode
|
|
|
|
*
|
|
|
|
* A List head should then be defined and initialized.
|
|
|
|
* @code
|
|
|
|
* Link_t xListHead;
|
|
|
|
* listINIT_HEAD( &xListHead );
|
|
|
|
* @endcode
|
|
|
|
*
|
|
|
|
* listADD can then be used to add nodes to the list.
|
|
|
|
* @code
|
|
|
|
* listADD( &( xListHead ), &( pxUserStruct->xLink ) );
|
|
|
|
* @endcode
|
|
|
|
*
|
|
|
|
* listFOR_EACH can be used for traversing the list.
|
|
|
|
* @code
|
|
|
|
* Link_t *pxLink;
|
|
|
|
* UserStruct_t *pxUserStruct;
|
|
|
|
* listFOR_EACH( pxLink, &( xListHead ) )
|
|
|
|
* {
|
|
|
|
* pxUserStruct = listCONTAINER( pxLink, UserStruct_t, xLink );
|
|
|
|
* }
|
|
|
|
* @endcode
|
|
|
|
*
|
|
|
|
* listFOR_EACH_SAFE should be used if you want to perform destructive operations
|
|
|
|
* (like free) on nodes while traversing the list.
|
|
|
|
* @code
|
|
|
|
* Link_t *pxLink, *pxTempLink;
|
|
|
|
* UserStruct_t *pxUserStruct;
|
|
|
|
* listFOR_EACH( pxLink, pxTempLink, &( xListHead ) )
|
|
|
|
* {
|
|
|
|
* pxUserStruct = listCONTAINER( pxLink, UserStruct_t, xLink );
|
|
|
|
* free( pxUserStruct );
|
|
|
|
* }
|
|
|
|
* @endcode
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _AWS_DOUBLY_LINKED_LIST_H_
|
|
|
|
#define _AWS_DOUBLY_LINKED_LIST_H_
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Struct embedded in any struct to make it a doubly linked
|
|
|
|
* list.
|
|
|
|
*
|
|
|
|
* pxNext in the head points to the first node in the list and pxPrev
|
|
|
|
* in the head points to the last node in the list. In case of empty
|
|
|
|
* list, both pxPrev and pxNext in the head point to the head node itself.
|
|
|
|
*/
|
|
|
|
typedef struct Link
|
|
|
|
{
|
|
|
|
struct Link * pxPrev; /**< Pointer to the previous node. */
|
|
|
|
struct Link * pxNext; /**< Pointer to the next node. */
|
|
|
|
} Link_t;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Initializes the given list head to an empty list.
|
|
|
|
*
|
|
|
|
* @param[in] pxHead The given list head to initialize.
|
|
|
|
*/
|
|
|
|
#define listINIT_HEAD( pxHead ) \
|
|
|
|
{ \
|
|
|
|
( pxHead )->pxPrev = ( pxHead ); \
|
|
|
|
( pxHead )->pxNext = ( pxHead ); \
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Adds the given new node to the given list.
|
|
|
|
*
|
|
|
|
* @param[in] pxHead The head of the given list.
|
|
|
|
* @param[in] pxLink The given new node to be added to the given
|
|
|
|
* list.
|
|
|
|
*/
|
|
|
|
#define listADD( pxHead, pxLink ) \
|
|
|
|
{ \
|
|
|
|
Link_t * pxPrevLink = ( pxHead ); \
|
|
|
|
Link_t * pxNextLink = ( ( pxHead )->pxNext ); \
|
|
|
|
\
|
|
|
|
( pxLink )->pxNext = pxNextLink; \
|
|
|
|
pxNextLink->pxPrev = ( pxLink ); \
|
|
|
|
pxPrevLink->pxNext = ( pxLink ); \
|
|
|
|
( pxLink )->pxPrev = ( pxPrevLink ); \
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Removes the given node from the list it is part of.
|
|
|
|
*
|
|
|
|
* If the given node is not a part of any list (i.e. next and previous
|
|
|
|
* nodes are NULL), nothing happens.
|
|
|
|
*
|
|
|
|
* @param[in] pxLink The given node to remove from the list.
|
|
|
|
*/
|
|
|
|
#define listREMOVE( pxLink ) \
|
|
|
|
{ \
|
|
|
|
/* If the link is part of a list, remove it from the list. */ \
|
|
|
|
if( ( pxLink )->pxNext != NULL && ( pxLink )->pxPrev != NULL ) \
|
|
|
|
{ \
|
|
|
|
( pxLink )->pxPrev->pxNext = ( pxLink )->pxNext; \
|
|
|
|
( pxLink )->pxNext->pxPrev = ( pxLink )->pxPrev; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
/* Make sure that this link is not part of any list anymore. */ \
|
|
|
|
( pxLink )->pxPrev = NULL; \
|
|
|
|
( pxLink )->pxNext = NULL; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Given the head of a list, checks if the list is empty.
|
|
|
|
*
|
|
|
|
* @param[in] pxHead The head of the given list.
|
|
|
|
*/
|
|
|
|
#define listIS_EMPTY( pxHead ) ( ( ( pxHead ) == NULL ) || ( ( pxHead )->pxNext == ( pxHead ) ) )
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Removes the first node from the given list and returns it.
|
|
|
|
*
|
|
|
|
* Removes the first node from the given list and assigns it to the
|
|
|
|
* pxLink parameter. If the list is empty, it assigns NULL to the
|
|
|
|
* pxLink.
|
|
|
|
*
|
|
|
|
* @param[in] pxHead The head of the list from which to remove the
|
|
|
|
* first node.
|
|
|
|
* @param[out] pxLink The output parameter to receive the removed
|
|
|
|
* node.
|
|
|
|
*/
|
|
|
|
#define listPOP( pxHead, pxLink ) \
|
|
|
|
{ \
|
|
|
|
if( listIS_EMPTY( ( pxHead ) ) ) \
|
|
|
|
{ \
|
|
|
|
( pxLink ) = NULL; \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
( pxLink ) = ( pxHead )->pxNext; \
|
|
|
|
/* If the link is part of a list, remove it from the list. */ \
|
|
|
|
if( ( pxLink )->pxNext != NULL && ( pxLink )->pxPrev != NULL ) \
|
|
|
|
{ \
|
|
|
|
( pxLink )->pxPrev->pxNext = ( pxLink )->pxNext; \
|
|
|
|
( pxLink )->pxNext->pxPrev = ( pxLink )->pxPrev; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
/* Make sure that this link is not part of any list anymore. */ \
|
|
|
|
( pxLink )->pxPrev = NULL; \
|
|
|
|
( pxLink )->pxNext = NULL; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Merges a list into a given list.
|
|
|
|
*
|
|
|
|
* @param[in] pxHeadResultList The head of the given list into which the
|
|
|
|
* other list should be merged.
|
|
|
|
* @param[in] pxHeadListToMerge The head of the list to be merged into the
|
|
|
|
* given list.
|
|
|
|
*/
|
|
|
|
#define listMERGE( pxHeadResultList, pxHeadListToMerge ) \
|
|
|
|
{ \
|
|
|
|
if( !listIS_EMPTY( ( pxHeadListToMerge ) ) ) \
|
|
|
|
{ \
|
|
|
|
/* Setup links between last node of listToMerge and first node of resultList. */ \
|
|
|
|
( pxHeadListToMerge )->pxPrev->pxNext = ( pxHeadResultList )->pxNext; \
|
|
|
|
( pxHeadResultList )->pxNext->pxPrev = ( pxHeadListToMerge )->pxPrev; \
|
|
|
|
\
|
|
|
|
/* Setup links between first node of listToMerge and the head of resultList. */ \
|
|
|
|
( pxHeadListToMerge )->pxNext->pxPrev = ( pxHeadResultList ); \
|
|
|
|
( pxHeadResultList )->pxNext = ( pxHeadListToMerge )->pxNext; \
|
|
|
|
/* Empty the merged list. */ \
|
|
|
|
listINIT_HEAD( ( pxHeadListToMerge ) ); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Helper macro to iterate over a list. pxLink contains the link node
|
|
|
|
* in each iteration.
|
|
|
|
*/
|
|
|
|
#define listFOR_EACH( pxLink, pxHead ) \
|
|
|
|
for( ( pxLink ) = ( pxHead )->pxNext; \
|
|
|
|
( pxLink ) != ( pxHead ); \
|
|
|
|
( pxLink ) = ( pxLink )->pxNext )
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Helper macro to iterate over a list. It is safe to destroy/free the
|
|
|
|
* nodes while iterating. pxLink contains the link node in each iteration.
|
|
|
|
*/
|
|
|
|
#define listFOR_EACH_SAFE( pxLink, pxTempLink, pxHead ) \
|
|
|
|
for( ( pxLink ) = ( pxHead )->pxNext, ( pxTempLink ) = ( pxLink )->pxNext; \
|
|
|
|
( pxLink ) != ( pxHead ); \
|
|
|
|
( pxLink ) = ( pxTempLink ), ( pxTempLink ) = ( pxLink )->pxNext )
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Given the pointer to the link member (of type Link_t) in a struct,
|
|
|
|
* extracts the pointer to the containing struct.
|
|
|
|
*
|
|
|
|
* @param[in] pxLink The pointer to the link member.
|
|
|
|
* @param[in] type The type of the containing struct.
|
|
|
|
* @param[in] member Name of the link member in the containing struct.
|
|
|
|
*/
|
|
|
|
#define listCONTAINER( pxLink, type, member ) ( ( type * ) ( ( uint8_t * ) ( pxLink ) - ( uint8_t * ) ( &( ( type * ) 0 )->member ) ) )
|
|
|
|
|
|
|
|
#endif /* _AWS_DOUBLY_LINKED_LIST_H_ */
|