/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ /** * @addtogroup DriverUtils * @{ * * @brief Defines common macros and interfaces of the driver module. * * This module provides interfaces such as log printing, doubly linked list operations, and work queues. * * @since 1.0 * @version 1.0 */ /** * @file hdf_dlist.h * * @brief Declares doubly linked list structures and interfaces. * * This file provides interfaces such as inserting a node from the head or tail of a doubly linked list, * checking whether a doubly linked list is empty, traversing a doubly linked list, and merging doubly linked lists. * * @since 1.0 * @version 1.0 */ #ifndef HDF_LIST_H #define HDF_LIST_H #include "hdf_base.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * @brief Describes a doubly linked list. */ struct DListHead { struct DListHead *next; /**< Pointer to the next node */ struct DListHead *prev; /**< Pointer to the previous node */ }; /** * @brief Initializes a doubly linked list. * * @param head Indicates the pointer to the linked list {@link DListHead}. The parameter cannot be empty. * @since 1.0 * @version 1.0 */ static inline void DListHeadInit(struct DListHead *head) { head->next = head; head->prev = head; } /** * @brief Checks whether a doubly linked list is empty. * * @param head Indicates the pointer to the linked list {@link DListHead}. The parameter cannot be empty. * @since 1.0 * @version 1.0 */ static inline bool DListIsEmpty(const struct DListHead *head) { return (head->next == head) ? true : false; } /** * @brief Removes a node from a doubly linked list. * * @param entry Indicates the pointer to the node to remove. For details, see {@link DListHead}. * The parameter cannot be empty. * @since 1.0 * @version 1.0 */ static inline void DListRemove(struct DListHead *entry) { entry->prev->next = entry->next; entry->next->prev = entry->prev; entry->prev = NULL; entry->next = NULL; } /** * @brief Inserts a node from the head of a doubly linked list. * * @param entry Indicates the pointer to the node to insert. For details, see {@link DListHead}. * The parameter cannot be empty. * @param head Indicates the pointer to the linked list {@link DListHead}. The parameter cannot be empty. * @since 1.0 * @version 1.0 */ static inline void DListInsertHead(struct DListHead *entry, struct DListHead *head) { entry->next = head->next; entry->prev = head; head->next->prev = entry; head->next = entry; } /** * @brief Inserts a node from the tail of a doubly linked list. * * @param entry Indicates the pointer to the node to insert. For details, see {@link DListHead}. * The parameter cannot be empty. * @param head Indicates the pointer to the linked list {@link DListHead}. The parameter cannot be empty. * @since 1.0 * @version 1.0 */ static inline void DListInsertTail(struct DListHead *entry, struct DListHead *head) { entry->next = head; entry->prev = head->prev; head->prev->next = entry; head->prev = entry; } /** * @brief Merges two linked lists by adding the list specified by list to * the head of the list specified by head and initializes the merged list. * * @param list Indicates the pointer to the linked list {@link DListHead}. The parameter cannot be empty. * @param head Indicates the pointer to the linked list {@link DListHead}. The parameter cannot be empty. * @since 1.0 * @version 1.0 */ static inline void DListMerge(struct DListHead *list, struct DListHead *head) { list->next->prev = head; list->prev->next = head->next; head->next->prev = list->prev; head->next = list->next; DListHeadInit(list); } static inline int DlistGetCount(const struct DListHead *head) { struct DListHead *next = head->next; int count = 0; while (next != head) { next = next->next; count++; } return count; } /** * @brief Obtains the address of a structure variable from its member address. * * @param ptr Indicates the structure member address. * @param type Indicates the structure type. * @param member Indicates the structure member. * @since 1.0 * @version 1.0 */ #define CONTAINER_OF(ptr, type, member) \ (type *)((char *)(ptr) - (char *)&((type *)0)->member) /** * @brief Obtains the first node of a doubly linked list. * * @param ptr Indicates the structure member address. * @param type Indicates the structure type. * @param member Indicates the structure member. * @since 1.0 * @version 1.0 */ #define DLIST_FIRST_ENTRY(ptr, type, member) \ CONTAINER_OF((ptr)->next, type, member) /** * @brief Obtains the last node of a doubly linked list. * * @param ptr Indicates the structure member address. * @param type Indicates the structure type. * @param member Indicates the structure member. * @since 1.0 * @version 1.0 */ #define DLIST_LAST_ENTRY(ptr, type, member) \ CONTAINER_OF((ptr)->prev, type, member) /** * @brief Traverses all nodes in a doubly linked list. * * @param pos Indicates the pointer to the structure variable. * @param head Indicates the pointer to the linked list head. * @param type Indicates the structure type. * @param member Indicates the member type of the structure. * @since 1.0 * @version 1.0 */ #define DLIST_FOR_EACH_ENTRY(pos, head, type, member) \ for ((pos) = CONTAINER_OF((head)->next, type, member); \ &(pos)->member != (head); \ (pos) = CONTAINER_OF((pos)->member.next, type, member)) #define DLIST_FOR_EACH_ENTRY_REVERSE(pos, head, type, member) \ for ((pos) = CONTAINER_OF((head)->prev, type, member); \ &(pos)->member != (head); \ (pos) = CONTAINER_OF((pos)->member.prev, type, member)) /** * @brief Traverses all nodes in a doubly linked list. * This function is used to delete the nodes pointed to by pos during traversal. * * @param pos Indicates the pointer to the structure variable. * @param tmp Indicates the pointer to the structure variable, pointing to the next node of pos. * @param head Indicates the pointer to the linked list head. * @param type Indicates the structure type. * @param member Indicates the member type of the structure. * @since 1.0 * @version 1.0 */ #define DLIST_FOR_EACH_ENTRY_SAFE(pos, tmp, head, type, member) \ for ((pos) = CONTAINER_OF((head)->next, type, member), \ (tmp) = CONTAINER_OF((pos)->member.next, type, member); \ &(pos)->member != (head); \ (pos) = (tmp), (tmp) = CONTAINER_OF((pos)->member.next, type, member)) #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* HDF_LIST_H */ /** @} */