You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
429 lines
14 KiB
C
429 lines
14 KiB
C
/*
|
|
* Typical data structures used.
|
|
* This library is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation; either version 2.1 of
|
|
* the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* (c) 2013-2014, 2015 Copyright Askele, inc. <http://askele.com>
|
|
* (c) 2013-2014, 2015 Copyright Askele Ingria, inc. <http://askele-ingria.com>
|
|
*/
|
|
|
|
#ifndef __TDATA_LIST_H__
|
|
#define __TDATA_LIST_H__
|
|
|
|
#include <sys/types.h>
|
|
#include <stdbool.h>
|
|
|
|
#define __MILESTONE ((unsigned long)0x123)
|
|
|
|
/**
|
|
* @def MILESTONES_SEQ(num) ((void *)__MILESTONE##num)
|
|
* @brief Easy way to define next item in milestones sequence
|
|
* @pararm num - number of milestone in sequence
|
|
*/
|
|
#define MILESTONES_SEQ(num) ((void *)(__MILESTONE + (num)))
|
|
|
|
/* milestones for list's next and prev pointers respectively */
|
|
#define MLST_LIST_NEXT MILESTONES_SEQ(1)
|
|
#define MLST_LIST_PREV MILESTONES_SEQ(2)
|
|
|
|
#ifndef offsetof
|
|
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
|
#endif
|
|
|
|
#ifndef container_of
|
|
#define container_of(PTR, TYPE, MEMBER) \
|
|
((TYPE *)((char *)(PTR) - offsetof(TYPE, MEMBER)))
|
|
#endif
|
|
|
|
/* init root node of non containerized double linked non cyclic list */
|
|
#define nclist_init_root(root) \
|
|
do { \
|
|
root->next = NULL; \
|
|
root->prev = root; \
|
|
} while (0)
|
|
|
|
/* add to tail of non containerized double linked non cyclic list */
|
|
#define nclist_add2tail(root,node) \
|
|
do { \
|
|
typeof(root) __tail = (root)->prev; \
|
|
\
|
|
__tail->next = node; \
|
|
node->prev = __tail; \
|
|
node->next = NULL; \
|
|
(root)->prev = node; \
|
|
} while (0)
|
|
|
|
#define nclist_for_each(root, node) \
|
|
for (node = root; node != NULL; node = node->next)
|
|
|
|
/**
|
|
* @typedef struct __list_node list_node_t
|
|
* @struct __list_node
|
|
* @brief List node
|
|
*/
|
|
typedef struct __list_node {
|
|
struct __list_node *next;
|
|
struct __list_node *prev;
|
|
} list_node_t;
|
|
|
|
/**
|
|
* @typedef struct __list_head list_head_t
|
|
* @struct __list_head
|
|
* @brief List head
|
|
* Actually list_head_t is the same as list_node_t, but
|
|
* they have different types though. That was done to prevent
|
|
* potentional errors(notice that list head is a stub, it's never
|
|
* tied with any real data and it's used only to determine where list
|
|
* starts and where it ends)
|
|
*/
|
|
typedef struct __list_head {
|
|
list_node_t head; /**< Head element of the list */
|
|
} list_head_t;
|
|
|
|
/**
|
|
* @def LIST_DEFINE(name)
|
|
* @brief Define and initialize list head with name @a name
|
|
* @param name - name of variable
|
|
*/
|
|
#define LIST_DEFINE(name) \
|
|
list_head_t name = { .head = { &(name).head, &(name).head } }
|
|
|
|
/**
|
|
* @fn static inline void list_init_head(list_head_t *lst)
|
|
* @brief Initialize list head
|
|
* @param lst - a pointer to list head.
|
|
*/
|
|
static inline void list_init_head(list_head_t *lst)
|
|
{
|
|
lst->head.next = lst->head.prev = &lst->head;
|
|
}
|
|
|
|
/**
|
|
* @fn static inline void list_init_node(list_node_t *node)
|
|
* @brief Initialize list node
|
|
* @param node - a pointer to free(unattached from list) node.
|
|
*/
|
|
static inline void list_init_node(list_node_t *node)
|
|
{
|
|
node->next = MLST_LIST_NEXT;
|
|
node->prev = MLST_LIST_PREV;
|
|
}
|
|
|
|
static inline bool list_node_next_isbound(list_node_t *node)
|
|
{
|
|
return (node->next == MLST_LIST_NEXT);
|
|
}
|
|
|
|
static inline bool list_node_prev_isbound(list_node_t *node)
|
|
{
|
|
return (node->prev == MLST_LIST_PREV);
|
|
}
|
|
|
|
/**
|
|
* @def list_entry(lst, nptr)
|
|
* @brief Get item that holds @a nptr node
|
|
* @param list - A pointer to the list
|
|
* @param nptr - A pointer to the node
|
|
* @return A pointer to the object given node contains
|
|
*/
|
|
#define list_entry(node, type, member) \
|
|
container_of(node, type, member)
|
|
|
|
|
|
|
|
/**
|
|
* @def list_head(lst)
|
|
* @brief Get head of the list
|
|
* @param lst - a pointer to list_head_t
|
|
* @return A pointer to header list_node_t
|
|
*/
|
|
#define list_head(lst) \
|
|
(&(lst)->head)
|
|
|
|
/**
|
|
* @def list_node_first(lst)
|
|
* @brief Get list's first node
|
|
* @param list - A pointer to the list_head_t
|
|
* @return A pointer to the list first node
|
|
*/
|
|
#define list_node_first(lst) \
|
|
((lst)->head.next)
|
|
|
|
/**
|
|
* list_first_entry - get the first element from a list
|
|
* @lst: the list head to take the element from.
|
|
* @type: the type of the struct this is embedded in.
|
|
* @member: the name of the list_struct within the struct.
|
|
*
|
|
* Note, that list is expected to be not empty.
|
|
*/
|
|
#define list_first_entry(lst, type, member) \
|
|
list_entry((lst)->head.next, type, member)
|
|
|
|
/**
|
|
* @def list_node_last(lst)
|
|
* @brief Get list's last node
|
|
* @param list - A pointer to the list_head_t
|
|
* @return A pointer to the list last node
|
|
*/
|
|
#define list_node_last(lst) \
|
|
((lst)->head.prev)
|
|
|
|
/**
|
|
* list_last_entry - get the last element from a list
|
|
* @lst: the list head to take the element from.
|
|
* @type: the type of the struct this is embedded in.
|
|
* @member: the name of the list_struct within the struct.
|
|
*
|
|
* Note, that list is expected to be not empty.
|
|
*/
|
|
#define list_last_entry(lst, type, member) \
|
|
list_entry((lst)->head.prev, type, member)
|
|
|
|
/**
|
|
* @def list_add2head(lst, new)
|
|
* @brief Add a node @a new to the head of the list
|
|
* @param lst - A pointer to the list
|
|
* @param new - A pointer to the list node
|
|
*/
|
|
#define list_add2head(lst, new) \
|
|
list_add(list_node_first(lst), new)
|
|
|
|
/**
|
|
* @def list_add2tail(lst, new)
|
|
* @brief Add a node @a new to the tail of the list
|
|
* @param lst - A pointer to the list
|
|
* @param new - A pointer to node to add
|
|
*/
|
|
#define list_add2tail(lst, new) \
|
|
list_add(list_head(lst), new)
|
|
|
|
/**
|
|
* @def list_delfromhead(lst)
|
|
* @brief Remove first element of the list
|
|
* @param lst - A pointer to the list
|
|
*/
|
|
#define list_delfromhead(lst) \
|
|
list_del(list_node_first(lst))
|
|
|
|
/**
|
|
* @def list_delfromtail(lst)
|
|
* @brief Remove the last element of the list
|
|
* @param list - A pointer to the list
|
|
*/
|
|
#define list_delfromtail(lst) \
|
|
list_del(list_node_last(lst))
|
|
|
|
/**
|
|
* @def list_del(del)
|
|
* @brief Remove node @a del from the list
|
|
* @param del - A node to remove
|
|
*/
|
|
#define list_del(del) \
|
|
(list_del_range(del, del))
|
|
|
|
/**
|
|
* @def list_add(before, new, after)
|
|
* @param after - will be the next node after @a new
|
|
* @param new - node to insert
|
|
*/
|
|
#define list_add(after, new) \
|
|
(list_add_range(new, new, (after)->prev, after))
|
|
|
|
/**
|
|
* @def list_move2head(to, from)
|
|
* @brief Move all nodes from list @a from to the head of list @a to
|
|
* @param to - destination list
|
|
* @param from - source list
|
|
*/
|
|
#define list_move2head(to, from) \
|
|
(list_move(list_head(to), list_node_first(to), from))
|
|
|
|
/**
|
|
* @def list_move2tail(to, from)
|
|
* @brief Move all nodes from list @a from to the tail of list @a to
|
|
* @param to - destination list
|
|
* @param from - source list
|
|
*/
|
|
#define list_move2tail(to, from) \
|
|
(list_move(list_node_last(to), list_head(to), from))
|
|
|
|
|
|
/**
|
|
* @def list_for_each(lst, liter)
|
|
* @brief Iterate through each element of the list
|
|
* @param lst - A pointer to list head
|
|
* @param liter - A pointer to list which will be used for iteration
|
|
*/
|
|
#define list_for_each(lst, liter) \
|
|
for (liter = list_node_first(lst); \
|
|
(liter) != list_head(lst); (liter) = (liter)->next)
|
|
|
|
/**
|
|
* @def list_for_each_safe(lst, liter, save)
|
|
* @brief Safe iteration through the list @a lst
|
|
*
|
|
* This iteration wouldn't be broken even if @a liter will be removed
|
|
* from the list
|
|
*
|
|
* @param lst - A pointer to the list head
|
|
* @param liter - A pointer to list node which will be used for iteration
|
|
* @param save - The same
|
|
*/
|
|
#define list_for_each_safe(lst, liter, save) \
|
|
for (liter = list_node_first(lst), save = (liter)->next; \
|
|
(liter) != list_head(lst); (liter) = (save), \
|
|
(save) = (liter)->next)
|
|
|
|
/**
|
|
* @def list_for_each_entry(lst, iter, member)
|
|
* @brief Iterate through each list node member
|
|
* @param lst - a pointer list head
|
|
* @param iter - a pointer to list entry using as iterator
|
|
* @param member - name of list node member in the parent structure
|
|
*/
|
|
#define list_for_each_entry(lst, iter, member) \
|
|
for (iter = list_entry(list_node_first(lst), typeof(*iter), member); \
|
|
&iter->member != list_head(lst); \
|
|
iter = list_entry(iter->member.next, typeof(*iter), member))
|
|
|
|
/**
|
|
* @def list_for_each_entry(lst, iter, member)
|
|
* @brief Iterate through each list node member and calls specified function with argument
|
|
* pointing to a list entry
|
|
*
|
|
* @param lst - a pointer list head
|
|
* @param iter - a pointer to list entry using as iterator
|
|
* @param member - name of list node member in the parent structure
|
|
* @param fn - function doing some actins against each entry of the list
|
|
*/
|
|
#define list_do_for_each_entry(lst, type, member, fn) \
|
|
{ \
|
|
type *t; \
|
|
list_node_t *node, *save; \
|
|
\
|
|
list_for_each_safe(lst, node, save) { \
|
|
t = container_of(node, type, member); \
|
|
fn(t); \
|
|
} \
|
|
}
|
|
|
|
/**
|
|
* @fn static inline int list_is_empty(list_t *list)
|
|
* @brief Determines if list @a list is empty
|
|
* @param list - A pointer to list to test
|
|
* @return True if list is empty, false otherwise
|
|
*/
|
|
static inline int list_is_empty(list_head_t *list)
|
|
{
|
|
return (list_node_first(list) == list_head(list));
|
|
}
|
|
|
|
/**
|
|
* @fn static inline void list_add_range(list_node_t *first, list_node_t *last,
|
|
* list_node_t *prev, list_node_t *next)
|
|
* @brief Insert a range of nodes from @a frist to @a last after @a prev and before @a last
|
|
* @param first - first node of range
|
|
* @param last - last node of range
|
|
* @param prev - after this node a range will be inserted
|
|
* @param next - before this node a range will be inserted
|
|
*/
|
|
static inline void list_add_range(list_node_t *first, list_node_t *last,
|
|
list_node_t *prev, list_node_t *next)
|
|
{
|
|
next->prev = last;
|
|
last->next = next;
|
|
prev->next = first;
|
|
first->prev = prev;
|
|
}
|
|
|
|
/* for internal usage */
|
|
static inline void __list_del_range(list_node_t *first, list_node_t *last)
|
|
{
|
|
first->prev->next = last->next;
|
|
last->next->prev = first->prev;
|
|
}
|
|
|
|
/**
|
|
* @fn static inline list_del_range(list_node_t *first, list_node_t *last)
|
|
* @brief Delete nodes from @a first to @a last from list.
|
|
* @param fist - first node to delete
|
|
* @param last - last node to delete
|
|
*/
|
|
static inline void list_del_range(list_node_t *first, list_node_t *last)
|
|
{
|
|
__list_del_range(first, last);
|
|
first->prev = MLST_LIST_PREV;
|
|
last->next = MLST_LIST_NEXT;
|
|
}
|
|
|
|
/**
|
|
* @fn static inline void list_cut_sublist(list_node_t *first, list_node_t *last)
|
|
* @brief Cut a "sublist" started from @a first and ended with @a last
|
|
*
|
|
* A @e "sublist" is similar to ordinary list except it hasn't a head.
|
|
* In other words it's a cyclic list in which all nodes are equitable.
|
|
*
|
|
* @param first - From this node sublist will be cutted
|
|
* @param last - The last node in the cutted sequence
|
|
*/
|
|
static inline void list_cut_sublist(list_node_t *first, list_node_t *last)
|
|
{
|
|
__list_del_range(first, last);
|
|
first->prev = last;
|
|
last->next = first;
|
|
}
|
|
|
|
/**
|
|
* @fn static inline void list_cut_head(list_head_t *head)
|
|
* @brief Cut a head from the list and make a "sublist"
|
|
* @param head - List's head that will be cutted.
|
|
* @see list_cut_sublist
|
|
* @see list_set_head
|
|
*/
|
|
static inline void list_cut_head(list_head_t *head)
|
|
{
|
|
list_cut_sublist(list_node_first(head), list_node_last(head));
|
|
}
|
|
|
|
/**
|
|
* @fn static inline void list_cut_head(list_head_t *head)
|
|
* @brief Attach a head to the sublist @a cyclist
|
|
* @param new_head - A head that will be attached
|
|
* @param cyclist - "sublist"
|
|
* @see list_cut_sublist
|
|
* @see list_set_head
|
|
*/
|
|
static inline void list_set_head(list_head_t *new_head, list_node_t *cyclist)
|
|
{
|
|
list_add_range(cyclist, cyclist->prev,
|
|
list_node_first(new_head), list_node_last(new_head));
|
|
}
|
|
|
|
/**
|
|
* @fn static inline void list_move(list_node_t *prev, list_node_t *next, list_head_t *from)
|
|
* @brief Insert nodes of list @a from after @a prev and before @a next
|
|
* @param prev - a node after which nodes of @a from will be inserted
|
|
* @param next - a node before which nodes of @a from will be inserted
|
|
*/
|
|
static inline void list_move(list_node_t *prev, list_node_t *next, list_head_t *from)
|
|
{
|
|
list_add_range(list_node_first(from), list_node_last(from),
|
|
prev, next);
|
|
list_init_head(from);
|
|
}
|
|
|
|
#endif /* __TDATA_LIST_H__ */
|
|
|