#ifndef __SR_LIST_H
#define __SR_LIST_H

#include "sr_stddef.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 ***********************************************************************************************************************
 * @struct      os_list_node
 *
 * @brief       Double List structure
 ***********************************************************************************************************************
 */
struct os_list_node
{
    struct os_list_node *next; /* Point to next node */
    struct os_list_node *prev; /* point to previous node */
};
typedef struct os_list_node os_list_node_t;

/**
 ***********************************************************************************************************************
 * @brief           Initialize a list head node or entry node.
 *
 * @param[in]       node            List head node or entry node to be initialized.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_init(os_list_node_t *node)
{
    node->next = node;
    node->prev = node;
}

/**
 ***********************************************************************************************************************
 * @brief           Add a new entry to list.
 *
 * @details         Insert a new entry after the specified head.
 *
 * @param[in]       head            List head to add it after.
 * @param[in]       entry           New entry to be added.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_add(os_list_node_t *head, os_list_node_t *entry)
{
    head->next->prev = entry;
    entry->next      = head->next;

    head->next  = entry;
    entry->prev = head;

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Add a new entry to list.
 *
 * @details         Insert a new entry before the specified head.
 *
 * @param[in]       head            List head to add it before.
 * @param[in]       entry           New entry to be added.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_add_tail(os_list_node_t *head, os_list_node_t *entry)
{
    head->prev->next = entry;
    entry->prev      = head->prev;

    head->prev  = entry;
    entry->next = head;

    return;
}

SR_INLINE void __os_list_del(os_list_node_t *prev, os_list_node_t *next)
{
    next->prev = prev;
    prev->next = next;

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Delete entry from list
 *
 * @param[in]       entry           The entry to delete from the list.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_del(os_list_node_t *entry)
{
    entry->next->prev = entry->prev;
    entry->prev->next = entry->next;

    entry->next = entry;
    entry->prev = entry;

    return;
}

SR_INLINE void __os_list_del_entry(os_list_node_t *entry)
{
    __os_list_del(entry->prev, entry->next);
    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Deletes entry from list and reinitialize it.
 *
 * @param[in]       entry           The entry to delete from the list.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_del_init(os_list_node_t *entry)
{
    __os_list_del_entry(entry);
    os_list_init(entry);

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Delete from one list and add as another's head.
 *
 * @param[in]       head            The head that will precede our entry.
 * @param[in]       entry           The entry to move.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_move(os_list_node_t *head, os_list_node_t *entry)
{
    __os_list_del_entry(entry);
    os_list_add(head, entry);

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Delete from one list and add as another's tail.
 *
 * @param[in]       head            The head that will follow our entry.
 * @param[in]       entry           The entry to move.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_move_tail(os_list_node_t *head, os_list_node_t *entry)
{
    __os_list_del_entry(entry);
    os_list_add_tail(head, entry);

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Tests whether a list is empty.
 *
 * @param[in]       head            The list to test.
 *
 * @return          Whether a list is empty.
 * @retval          SR_TRUE         The list is empty.
 * @retval          SR_FALSE        The list is not empty.
 ***********************************************************************************************************************
 */
SR_INLINE srBool_t os_list_empty(const os_list_node_t *head)
{
    return (head->next == head);
}

/**
 ***********************************************************************************************************************
 * @brief           Calculate entry count of a list.
 *
 * @param[in]       head            The list to calculate entry count.
 *
 * @return          Entry count of the list.
 ***********************************************************************************************************************
 */
SR_INLINE uint32_t os_list_len(const os_list_node_t *head)
{
    uint32_t              len;
    const os_list_node_t *node;

    len  = 0;
    node = head;

    while (node->next != head)
    {
        node = node->next;
        len++;
    }

    return len;
}

SR_INLINE void __os_list_splice(os_list_node_t *head, os_list_node_t *list)
{
    os_list_node_t *first;
    os_list_node_t *last;
    os_list_node_t *at;

    first = list->next;
    last  = list->prev;
    at    = head->next;

    first->prev = head;
    head->next  = first;

    last->next = at;
    at->prev   = last;

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Join two lists.
 *
 * @param[in]       head            The place to add it in the second list.
 * @param[in]       list            The new list to add.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_splice(os_list_node_t *head, os_list_node_t *list)
{
    if (!os_list_empty(list))
    {
        __os_list_splice(head, list);
    }

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Join two lists and reinitialise the emptied list.
 *
 * @attention       The list at @list is reinitialised
 *
 * @param[in]       head            The place to add it in the second list.
 * @param[in]       list            The new list to add.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_list_splice_init(os_list_node_t *head, os_list_node_t *list)
{
    if (!os_list_empty(list))
    {
        __os_list_splice(head, list);
        os_list_init(list);
    }

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Return first entry of a list.
 *
 * @param[in]       head            The list to find first entry.
 *
 * @return          The first entry.
 * @retval          SR_NULL         The list is empty, not found first entry.
 * @retval          else            The first entry of the list.
 ***********************************************************************************************************************
 */
SR_INLINE os_list_node_t *os_list_first(os_list_node_t *head)
{
    if (head->next == head)
    {
        return SR_NULL;
    }

    return head->next;
}

/**
 ***********************************************************************************************************************
 * @brief           Return last entry of a list.
 *
 * @param[in]       head            The list to find last entry.
 *
 * @return          The last entry.
 * @retval          SR_NULL         The list is empty, not found last entry.
 * @retval          else            The last entry of the list.
 ***********************************************************************************************************************
 */
SR_INLINE os_list_node_t *os_list_tail(os_list_node_t *head)
{
    os_list_node_t *node;

    if (head->next == head)
    {
        return SR_NULL;
    }

    node = head;
    while (node->next != head)
    {
        node = node->next;
    }

    return node;
}

/* Initialize a double list, this micro is only as right value */
#define OS_LIST_INIT(name)                                                                                             \
    {                                                                                                                  \
        &(name), &(name)                                                                                               \
    }

/**
 ***********************************************************************************************************************
 * @def         os_list_entry
 *
 * @brief       Get the struct for this entry
 *
 * @param       ptr             The &struct os_list_node pointer.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the list_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_list_entry(ptr, type, member) SR_CONTAINER_OF(ptr, type, member)

/**
 ***********************************************************************************************************************
 * @def         os_list_first_entry
 *
 * @brief       Get the first entry from a list
 *
 * @attention   That list is expected to be not empty.
 *
 * @param       head            The list head to take the entry from.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the list_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_list_first_entry(head, type, member) os_list_entry((head)->next, type, member)

/**
 ***********************************************************************************************************************
 * @def         os_list_first_entry_or_null
 *
 * @brief       Get the first entry from a list
 *
 * @attention   That list may be empty. If empty, return SR_NULL.
 *
 * @param       head            The list head to take the entry from.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the list_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_list_first_entry_or_null(head, type, member)                                                                \
    (!os_list_empty(head) ? os_list_first_entry(head, type, member) : SR_NULL)

/**
 ***********************************************************************************************************************
 * @def         os_list_tail_entry
 *
 * @brief       Get the last entry from a list
 *
 * @attention   That list is expected to be not empty.
 *
 * @param       head            The list head to take the entry from.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the list_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_list_tail_entry(head, type, member) os_list_entry(os_list_tail(head), type, member)

/**
 ***********************************************************************************************************************
 * @def         os_list_tail_entry_or_null
 *
 * @brief       Get the last entry from a list
 *
 * @attention   That list may be empty. If empty, return SR_NULL.
 *
 * @param       head            The list head to take the entry from.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the list_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_list_tail_entry_or_null(head, type, member)                                                                 \
    (!os_list_empty(head) ? os_list_tail_entry(head, type, member) : SR_NULL)

/**
 ***********************************************************************************************************************
 * @def         os_list_for_each
 *
 * @brief       Iterate over a list
 *
 * @param       pos             The &struct os_list_node to use as a loop counter.
 * @param       head            The head for your list.
 ***********************************************************************************************************************
 */
#define os_list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)

/**
 ***********************************************************************************************************************
 * @def         os_list_for_each_safe
 *
 * @brief       Iterate over a list safe against removal of list entry
 *
 * @param       pos             The &struct os_list_node to use as a loop counter.
 * @param       n               Another &struct os_list_node to use as temporary storage
 * @param       head            The head for your list.
 ***********************************************************************************************************************
 */
#define os_list_for_each_safe(pos, n, head)                                                                            \
    for (pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next)

/**
 ***********************************************************************************************************************
 * @def         os_list_for_each_entry
 *
 * @brief       Iterate over list of given type
 *
 * @param       pos             The type * to use as a loop counter.
 * @param       head            The head for your list.
 * @param       type            The type of the struct same as pos(loop counter).
 * @param       member          The name of the os_list_node within the struct.
 ***********************************************************************************************************************
 */
#define os_list_for_each_entry(pos, head, type, member)                                                                \
    for (pos = os_list_entry((head)->next, type, member); &pos->member != (head);                                      \
         pos = os_list_entry(pos->member.next, type, member))
         
//反向遍历
#define os_list_for_each_entry_rev(pos, head, type, member)                                                                \
    for (pos = os_list_entry((head)->prev, type, member); &pos->member != (head);                                      \
         pos = os_list_entry(pos->member.prev, type, member))


/**
 ***********************************************************************************************************************
 * @def         os_list_for_each_entry_safe
 *
 * @brief       Iterate over list of given type safe against removal of list entry.
 *
 * @param       pos             The type * to use as a loop counter.
 * @param       n               Another type * to use as temporary storage.
 * @param       head            The head for your list.
 * @param       type            The type of the struct same as pos(loop counter).
 * @param       member          The name of the os_list_node within the struct.
 ***********************************************************************************************************************
 */
#define os_list_for_each_entry_safe(pos, n, head, type, member)                                                        \
    for (pos = os_list_entry((head)->next, type, member), n = os_list_entry(pos->member.next, type, member);           \
         &pos->member != (head);                                                                                       \
         pos = n, n = os_list_entry(n->member.next, type, member))

/**
 ***********************************************************************************************************************
 * @struct      os_slist_node
 *
 * @brief       Single List structure
 ***********************************************************************************************************************
 */
struct os_slist_node
{
    struct os_slist_node *next; /* Point to next node */
};
typedef struct os_slist_node os_slist_node_t;

/**
 ***********************************************************************************************************************
 * @brief           Initialize a single list
 *
 * @param[in]       node            The single list to be initialized
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_slist_init(os_slist_node_t *node)
{
    node->next = SR_NULL;
    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Add a new entry to front of a list.
 *
 *
 * @param[in]       head            List head.
 * @param[in]       entry           New entry to be added.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_slist_add(os_slist_node_t *head, os_slist_node_t *entry)
{
    entry->next = head->next;
    head->next  = entry;

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Add a new entry to tail of a list.
 *
 *
 * @param[in]       head            List head.
 * @param[in]       entry           New entry to be added.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_slist_add_tail(os_slist_node_t *head, os_slist_node_t *entry)
{
    os_slist_node_t *node;

    node = head;
    while (node->next)
    {
        node = node->next;
    }

    /* append the node to the tail */
    node->next  = entry;
    entry->next = SR_NULL;

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Delete entry from list
 *
 * @param[in]       head            List head.
 * @param[in]       entry           The entry to delete from the list.
 *
 * @return          No return value.
 ***********************************************************************************************************************
 */
SR_INLINE void os_slist_del(os_slist_node_t *head, os_slist_node_t *entry)
{
    os_slist_node_t *node;

    node = head;
    while (node->next && (node->next != entry))
    {
        node = node->next;
    }

    /* del entry node */
    if (node->next != SR_NULL)
    {
        node->next = node->next->next;
    }

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Calculate entry count of a list.
 *
 * @param[in]       head            The list to calculate entry count.
 *
 * @return          Entry count of the list.
 ***********************************************************************************************************************
 */
SR_INLINE uint32_t os_slist_len(const os_slist_node_t *head)
{
    uint32_t               len;
    const os_slist_node_t *node;

    len  = 0;
    node = head->next;

    while (node != SR_NULL)
    {
        node = node->next;
        len++;
    }

    return len;
}

/**
 ***********************************************************************************************************************
 * @brief           Return first entry of a list.
 *
 * @param[in]       head            The list to find first entry.
 *
 * @return          The first entry.
 * @retval          SR_NULL         The list is empty, not found first entry.
 * @retval          else            The first entry of the list.
 ***********************************************************************************************************************
 */
SR_INLINE os_slist_node_t *os_slist_first(os_slist_node_t *head)
{
    return head->next;
}

/**
 ***********************************************************************************************************************
 * @brief           Return last entry of a list.
 *
 * @param[in]       head            The list to find last entry.
 *
 * @return          The last entry.
 * @retval          SR_NULL         The list is empty, not found last entry.
 * @retval          else            The last entry of the list.
 ***********************************************************************************************************************
 */
SR_INLINE os_slist_node_t *os_slist_tail(os_slist_node_t *head)
{
    os_slist_node_t *node;

    if (head->next == SR_NULL)
    {
        return SR_NULL;
    }

    node = head;
    while (node->next)
    {
        node = node->next;
    }

    return node;
}

/**
 ***********************************************************************************************************************
 * @brief           Return next entry of current entry.
 *
 * @param[in]       node            Current entry.
 *
 * @return          The next entry of current entry.
 * @retval          SR_NULL         The current entry is last, not found next entry.
 * @retval          else            The next entry of current entry.
 ***********************************************************************************************************************
 */
SR_INLINE os_slist_node_t *os_slist_next(os_slist_node_t *node)
{
    return node->next;
}

/**
 ***********************************************************************************************************************
 * @brief           Tests whether a list is empty.
 *
 * @param[in]       head            The list to test.
 *
 * @return          Whether a list is empty.
 * @retval          SR_TRUE         The list is empty.
 * @retval          SR_FALSE        The list is not empty.
 ***********************************************************************************************************************
 */
SR_INLINE srBool_t os_slist_empty(os_slist_node_t *head)
{
    return (head->next == SR_NULL);
}

/* Initialize a single list, this micro is only as right value */
#define OS_SLIST_INIT(name)                                                                                            \
    {                                                                                                                  \
        SR_NULL                                                                                                        \
    }

/**
 ***********************************************************************************************************************
 * @def         os_slist_entry
 *
 * @brief       Get the struct for this entry
 *
 * @param       ptr             The &struct os_slist_node pointer.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the slist_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_slist_entry(ptr, type, member) SR_CONTAINER_OF(ptr, type, member)

/**
 ***********************************************************************************************************************
 * @def         os_slist_for_each
 *
 * @brief       Iterate over a list
 *
 * @param       pos             The &struct os_slist_node to use as a loop counter.
 * @param       head            The head for your list.
 ***********************************************************************************************************************
 */
#define os_slist_for_each(pos, head) for (pos = (head)->next; pos != SR_NULL; pos = pos->next)

/**
 ***********************************************************************************************************************
 * @def         os_slist_for_each_safe
 *
 * @brief       Iterate over a list safe against removal of list entry
 *
 * @param       pos             The &struct os_slist_node to use as a loop counter.
 * @param       n               Another &struct os_slist_node to use as temporary storage
 * @param       head            The head for your list.
 ***********************************************************************************************************************
 */
#define os_slist_for_each_safe(pos, n, head)                                                                           \
    for (pos = (head)->next, n = (pos != SR_NULL) ? pos->next : SR_NULL; pos != SR_NULL;                               \
         pos = n, n = (pos != SR_NULL) ? pos->next : SR_NULL)

/**
 ***********************************************************************************************************************
 * @def         os_slist_first_entry
 *
 * @brief       Get the first entry from a list
 *
 * @attention   That list is expected to be not empty.
 *
 * @param       head            The list head to take the entry from.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the slist_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_slist_first_entry(head, type, member) os_slist_entry((head)->next, type, member)

/**
 ***********************************************************************************************************************
 * @def         os_slist_first_entry_or_null
 *
 * @brief       Get the first entry from a list
 *
 * @attention   That list may be empty. If empty, return SR_NULL.
 *
 * @param       head            The list head to take the entry from.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the slist_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_slist_first_entry_or_null(head, type, member)                                                               \
    (!os_slist_empty(head) ? os_slist_first_entry(head, type, member) : SR_NULL)

/**
 ***********************************************************************************************************************
 * @def         os_slist_tail_entry
 *
 * @brief       Get the last entry from a list
 *
 * @attention   That list is expected to be not empty.
 *
 * @param       head            The list head to take the entry from.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the slist_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_slist_tail_entry(head, type, member) os_slist_entry(os_slist_tail(head), type, member)

/**
 ***********************************************************************************************************************
 * @def         os_slist_tail_entry_or_null
 *
 * @brief       Get the last entry from a list
 *
 * @attention   That list may be empty. If empty, return SR_NULL.
 *
 * @param       head            The list head to take the entry from.
 * @param       type            The type of the struct this is embedded in.
 * @param       member          The name of the list_struct within the struct.
 ***********************************************************************************************************************
 */
#define os_slist_tail_entry_or_null(head, type, member)                                                                \
    (!os_slist_empty(head) ? os_slist_tail_entry(head, type, member) : SR_NULL)

#ifdef __cplusplus
}
#endif

#endif /* __OS_LIST_H__ */
