249 lines
6.3 KiB
C
Executable File
249 lines
6.3 KiB
C
Executable File
/**
|
|
* @file pslist.h
|
|
* @author LokLiang (lokliang@163.com)
|
|
* @brief
|
|
* @version 0.1
|
|
* @date 2023-05-01
|
|
*
|
|
* @copyright Copyright (c) 2023
|
|
*
|
|
*/
|
|
|
|
#ifndef __PSLIST_H__
|
|
#define __PSLIST_H__
|
|
|
|
#include "sys_types.h"
|
|
|
|
typedef struct _psnode sys_psnode_t;
|
|
|
|
typedef struct _pslist sys_pslist_t;
|
|
|
|
struct _psnode
|
|
{
|
|
sys_psnode_t *const *next;
|
|
};
|
|
|
|
struct _pslist
|
|
{
|
|
sys_psnode_t *const *head;
|
|
sys_psnode_t *const *tail;
|
|
};
|
|
|
|
#define _CONTAINER_OF(PTR, TYPE, MEMBER) ((TYPE *)&((uint8_t *)PTR)[-(int)&((TYPE *)0)->MEMBER])
|
|
|
|
#define SYS_PSLIST_FOR_EACH_NODE(__sl, __sn) \
|
|
for (__sn = sys_pslist_peek_head(__sl); __sn; \
|
|
__sn = sys_pslist_peek_next(__sn))
|
|
|
|
#define SYS_PSLIST_ITERATE_FROM_NODE(__sl, __sn) \
|
|
for (__sn = __sn ? sys_pslist_peek_next_no_check(__sn) \
|
|
: sys_pslist_peek_head(__sl); \
|
|
__sn; \
|
|
__sn = sys_pslist_peek_next(__sn))
|
|
|
|
#define SYS_PSLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
|
|
for (__sn = sys_pslist_peek_head(__sl), \
|
|
__sns = sys_pslist_peek_next(__sn); \
|
|
__sn; \
|
|
__sn = __sns, __sns = sys_pslist_peek_next(__sn))
|
|
|
|
#define SYS_PSLIST_CONTAINER(__ln, __cn, __n) \
|
|
((__ln) ? _CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL)
|
|
|
|
#define SYS_PSLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \
|
|
SYS_PSLIST_CONTAINER(sys_pslist_peek_head(__sl), __cn, __n)
|
|
|
|
#define SYS_PSLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \
|
|
SYS_PSLIST_CONTAINER(sys_pslist_peek_tail(__sl), __cn, __n)
|
|
|
|
#define SYS_PSLIST_PEEK_NEXT_CONTAINER(__cn, __n) \
|
|
((__cn) ? SYS_PSLIST_CONTAINER(sys_pslist_peek_next(&((__cn)->__n)), \
|
|
__cn, __n) \
|
|
: NULL)
|
|
|
|
#define SYS_PSLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
|
|
for (__cn = SYS_PSLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); \
|
|
__cn; \
|
|
__cn = SYS_PSLIST_PEEK_NEXT_CONTAINER(__cn, __n))
|
|
|
|
#define SYS_PSLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
|
|
for (__cn = SYS_PSLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
|
|
__cns = SYS_PSLIST_PEEK_NEXT_CONTAINER(__cn, __n); \
|
|
__cn; \
|
|
__cn = __cns, __cns = SYS_PSLIST_PEEK_NEXT_CONTAINER(__cn, __n))
|
|
|
|
__static_inline void sys_pslist_init(sys_pslist_t *list)
|
|
{
|
|
list->head = NULL;
|
|
list->tail = NULL;
|
|
}
|
|
|
|
#define SYS_PSLIST_STATIC_INIT(ptr_to_list) \
|
|
{ \
|
|
NULL, NULL \
|
|
}
|
|
|
|
__static_inline bool sys_pslist_is_empty(sys_pslist_t *list)
|
|
{
|
|
return (!list->head);
|
|
}
|
|
|
|
__static_inline sys_psnode_t *const *sys_pslist_peek_head(sys_pslist_t *list)
|
|
{
|
|
return list->head;
|
|
}
|
|
|
|
__static_inline sys_psnode_t *const *sys_pslist_peek_tail(sys_pslist_t *list)
|
|
{
|
|
return list->tail;
|
|
}
|
|
|
|
__static_inline sys_psnode_t *const *sys_pslist_peek_next_no_check(sys_psnode_t *const *node)
|
|
{
|
|
return (*node)->next;
|
|
}
|
|
|
|
__static_inline sys_psnode_t *const *sys_pslist_peek_next(sys_psnode_t *const *node)
|
|
{
|
|
return node ? sys_pslist_peek_next_no_check(node) : NULL;
|
|
}
|
|
|
|
__static_inline void sys_pslist_prepend(sys_pslist_t *list,
|
|
sys_psnode_t *const *node)
|
|
{
|
|
(*node)->next = list->head;
|
|
list->head = node;
|
|
|
|
if (!list->tail)
|
|
{
|
|
list->tail = list->head;
|
|
}
|
|
}
|
|
|
|
__static_inline void sys_pslist_append(sys_pslist_t *list,
|
|
sys_psnode_t *const *node)
|
|
{
|
|
(*node)->next = NULL;
|
|
|
|
if (!list->tail)
|
|
{
|
|
list->tail = node;
|
|
list->head = node;
|
|
}
|
|
else
|
|
{
|
|
(*(list->tail))->next = node;
|
|
list->tail = node;
|
|
}
|
|
}
|
|
|
|
__static_inline void sys_pslist_append_list(sys_pslist_t *list,
|
|
sys_psnode_t *const *head, sys_psnode_t *const *tail)
|
|
{
|
|
if (!list->tail)
|
|
{
|
|
list->head = head;
|
|
list->tail = tail;
|
|
}
|
|
else
|
|
{
|
|
(*(list->tail))->next = head;
|
|
list->tail = tail;
|
|
}
|
|
}
|
|
|
|
__static_inline void sys_pslist_merge_pslist(sys_pslist_t *list,
|
|
sys_pslist_t *list_to_append)
|
|
{
|
|
sys_pslist_append_list(list, list_to_append->head,
|
|
list_to_append->tail);
|
|
sys_pslist_init(list_to_append);
|
|
}
|
|
|
|
__static_inline void sys_pslist_insert(sys_pslist_t *list,
|
|
sys_psnode_t *const *prev,
|
|
sys_psnode_t *const *node)
|
|
{
|
|
if (!prev)
|
|
{
|
|
sys_pslist_prepend(list, node);
|
|
}
|
|
else if (!(*prev)->next)
|
|
{
|
|
sys_pslist_append(list, node);
|
|
}
|
|
else
|
|
{
|
|
(*node)->next = (*prev)->next;
|
|
(*prev)->next = node;
|
|
}
|
|
}
|
|
|
|
__static_inline sys_psnode_t *const *sys_pslist_get_not_empty(sys_pslist_t *list)
|
|
{
|
|
sys_psnode_t *const *node = list->head;
|
|
|
|
list->head = (*node)->next;
|
|
if (list->tail == node)
|
|
{
|
|
list->tail = list->head;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
__static_inline sys_psnode_t *const *sys_pslist_get(sys_pslist_t *list)
|
|
{
|
|
return sys_pslist_is_empty(list) ? NULL : sys_pslist_get_not_empty(list);
|
|
}
|
|
|
|
__static_inline void sys_pslist_remove(sys_pslist_t *list,
|
|
sys_psnode_t *const *prev_node,
|
|
sys_psnode_t *const *node)
|
|
{
|
|
if (!prev_node)
|
|
{
|
|
list->head = (*node)->next;
|
|
|
|
/* Was node also the tail? */
|
|
if (list->tail == node)
|
|
{
|
|
list->tail = list->head;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*prev_node)->next = (*node)->next;
|
|
|
|
/* Was node the tail? */
|
|
if (list->tail == node)
|
|
{
|
|
list->tail = prev_node;
|
|
}
|
|
}
|
|
|
|
(*node)->next = NULL;
|
|
}
|
|
|
|
__static_inline bool sys_pslist_find_and_remove(sys_pslist_t *list,
|
|
sys_psnode_t *const *node)
|
|
{
|
|
sys_psnode_t *const *prev = NULL;
|
|
sys_psnode_t *const *test;
|
|
|
|
SYS_PSLIST_FOR_EACH_NODE(list, test)
|
|
{
|
|
if (test == node)
|
|
{
|
|
sys_pslist_remove(list, prev, node);
|
|
return true;
|
|
}
|
|
|
|
prev = test;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endif
|