/*
* 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 */
/** @} */