/**
 * @file hv_comm_LinkedList.h
 * @brief Header file of LinkedList.
 *
 * @verbatim
 * ==============================================================================
 *                        ##### How to use #####
 * ==============================================================================
 *
 *
 * @endverbatim
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2023-05-18
 */

#ifndef __SDK_COMMON_UTIL_HVQUEUE_INC_LINKED_LIST_H__
#define __SDK_COMMON_UTIL_HVQUEUE_INC_LINKED_LIST_H__

#include "hv_comm_DataType.h"
#include "stddef.h"

struct LinkedList
{
    struct LinkedList *next;
    struct LinkedList *prev;
};

#define Hv_Comm_LinkedList_Entry(ptr, type, elem)                                         \
    ((type *) ((char *) (ptr) -offsetof(type, elem)))

/**
 * Call once to initialize.
 * @param LinkedList *list
 */
VOID Hv_Comm_LinkedList_Init(struct LinkedList *list);

/**
 * @param LinkedList *list
 */
VOID Hv_Comm_LinkedList_Clear(struct LinkedList *list);

/**
 * @param LinkedList *list
 * @return     'true' if empty
 */
BOOL Hv_Comm_LinkedList_IsEmpty(struct LinkedList *list);

/**
 * @param LinkedList *list
 * @return     element count in the list, beware this is a log(n) operation.
 */
UINT32 Hv_Comm_LinkedList_Count(struct LinkedList *list);

/**
 * @param LinkedList *list
 * @return     returns head. If list is empty, returns NULL.
 */
struct LinkedList *Hv_Comm_LinkedList_Head(struct LinkedList *list);

/**
 * @param LinkedList *list
 * @return     returns tail. If list is empty, returns NULL.
 */
struct LinkedList *Hv_Comm_LinkedList_Tail(struct LinkedList *list);

/**
 *  before : [head]item1 -> [tail]item2
 *  after  : [head]'elem' -> item1 -> [tail]item2
 *
 * @param LinkedList *list
 * @param elem elem to add to the head
 */
VOID Hv_Comm_LinkedList_AddHead(struct LinkedList *list, struct LinkedList *elem);

/**
 *  before : [head]item1 -> item2 -> item3
 *  after  : [head]item2 -> item3
 *
 * @param LinkedList *list
 * @return     head element, if list is empty, returns NULL.
 */
struct LinkedList *Hv_Comm_LinkedList_PopHead(struct LinkedList *list);

/**
 *  before : [head]item1 -> [tail]item2
 *  after  : [head]item1 -> item2 -> [tail]'elem'
 *
 * @param LinkedList *list
 * @param elem elem to append to the tail
 */
VOID Hv_Comm_LinkedList_AddTail(struct LinkedList *list, struct LinkedList *elem);

/**
 *  before : [head]item1 -> item2 -> item3
 *  after  : [head]item1 -> item2
 *
 * @param LinkedList *list
 * @return     head element, if list is empty, returns NULL.
 */
struct LinkedList *Hv_Comm_LinkedList_PopTail(struct LinkedList *list);

/**
 *  before : item1 -> 'prev' -> item2
 *  after  : item1 -> 'prev' -> 'elem' -> item2
 *
 * @param LinkedList *list
 * @param prev previous element of the 'elem'
 * @param elem elem to be added after 'prev'
 */
VOID Hv_Comm_LinkedList_AddAfter(struct LinkedList *list, struct LinkedList *prev,
                       struct LinkedList *elem);

/**
 *  before : item1 -> 'next' -> item2
 *  after  : item1 -> 'elem'-> 'next' -> item2
 *
 * @param LinkedList *list
 * @param next next element of the 'elem'
 * @param elem elem to be added before 'next'
 */
VOID Hv_Comm_LinkedList_AddBefore(struct LinkedList *list, struct LinkedList *next,
                        struct LinkedList *elem);

/**
 *  before : item1 -> 'elem' -> item2
 *  after  : item1 -> item2
 *
 * @param LinkedList *list pointer
 * @param elem elem to be deleted
 */
VOID Hv_Comm_LinkedList_Del(struct LinkedList *list, struct LinkedList *elem);

/**
 * struct container {
 *      struct LinkedList others;
 * };
 *
 * struct container *container; // User object
 * struct LinkedList *list;        // List pointer, should already be initialized.
 * struct LinkedList *it;          // Iterator
 *
 * Hv_Comm_LinkedList_ForEach (list, it) {
 *       container = Hv_Comm_LinkedList_Entry(it, struct container, others);
 * }
 */
#define Hv_Comm_LinkedList_ForEach(list, elem)                                            \
    for ((elem) = (list)->next; (elem) != (list); (elem) = (elem)->next)

/**
 *  It is safe to delete items from the list while using this iterator.
 *
 * struct container {
 *      struct LinkedList others;
 * };
 *
 * struct container *container; // User object
 * struct LinkedList *list;        // List pointer, should already be initialized.
 * struct LinkedList *tmp;         // Variable for loop, user should not use this.
 * struct LinkedList *it;          // Iterator
 *
 * Hv_Comm_LinkedList_ForEachSafe (list, it) {
 *       container = Hv_Comm_LinkedList_Entry(it, struct container, others);
 *       Hv_Comm_LinkedList_Del(list, &container->others);
 * }
 */
#define Hv_Comm_LinkedList_ForEachSafe(list, n, elem)                                    \
    for ((elem) = (list)->next, (n) = (elem)->next; (elem) != (list);          \
         (elem) = (n), (n) = (elem)->next)

/**
 * Reverse iterator
 *
 * struct container {
 *      struct LinkedList others;
 * };
 *
 * struct container *container; // User object
 * struct LinkedList *list;        // List pointer, should already be initialized.
 * struct LinkedList *it;          // Iterator
 *
 * Hv_Comm_LinkedList_ForEach_r (list, it) {
 *       container = Hv_Comm_LinkedList_Entry(it, struct container, others);
 * }
 */
#define Hv_Comm_LinkedList_ForEachR(list, elem)                                          \
    for ((elem) = (list)->prev; (elem) != (list); (elem) = (elem)->prev)


/**
 *  Reverse iterator.
 *
 *  It is safe to delete items from the list while using
 *  this iterator.
 *
 * struct container {
 *      struct LinkedList others;
 * };
 *
 * struct container *container; // User object
 * struct LinkedList *list;        // List pointer, should already be initialized.
 * struct LinkedList *tmp;         // Variable for loop, user should not use this.
 * struct LinkedList *it;          // Iterator
 *
 * Hv_Comm_LinkedList_ForEachSafe_r (list, tmp, it) {
 *       container = Hv_Comm_LinkedList_Entry(it, struct container, others);
 *       Hv_Comm_LinkedList_Del(list, &container->others);
 * }
 */
#define Hv_Comm_LinkedList_ForEachSafeR(list, n, elem)                                  \
    for ((elem) = (list)->prev, (n) = (elem)->prev; (elem) != (list);          \
         (elem) = (n), (n) = (elem)->prev)

#endif
