/* Doubly linked list macros compatible with Linux kernel's version * Copyright (c) 2015 by Takashi Iwai * * 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, or (at your option) any later version. * * This program 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. */ #ifndef _LIST_H #define _LIST_H #include struct list_head { struct list_head *next; struct list_head *prev; }; /* one-shot definition of a list head */ #define LIST_HEAD(x) \ struct list_head x = { &x, &x } /* initialize a list head explicitly */ static inline void INIT_LIST_HEAD(struct list_head *p) { p->next = p->prev = p; } #define list_entry_offset(p, type, offset) \ ((type *)((char *)(p) - (offset))) /* list_entry - retrieve the original struct from list_head * @p: list_head pointer * @type: struct type * @member: struct field member containing the list_head */ #define list_entry(p, type, member) \ list_entry_offset(p, type, offsetof(type, member)) /* list_for_each - iterate over the linked list * @p: iterator, a list_head pointer variable * @list: list_head pointer containing the list */ #define list_for_each(p, list) \ for (p = (list)->next; p != (list); p = p->next) /* list_for_each_safe - iterate over the linked list, safe to delete * @p: iterator, a list_head pointer variable * @s: a temporary variable to keep the next, a list_head pointer, too * @list: list_head pointer containing the list */ #define list_for_each_safe(p, s, list) \ for (p = (list)->next; s = p->next, p != (list); p = s) /* list_add - prepend a list entry at the head * @p: the new list entry to add * @list: the list head */ static inline void list_add(struct list_head *p, struct list_head *list) { struct list_head *first = list->next; p->next = first; first->prev = p; list->next = p; p->prev = list; } /* list_add_tail - append a list entry at the tail * @p: the new list entry to add * @list: the list head */ static inline void list_add_tail(struct list_head *p, struct list_head *list) { struct list_head *last = list->prev; last->next = p; p->prev = last; p->next = list; list->prev = p; } /* list_insert - insert a new list entry between two known consecutive entries * @p: the new entry to be inserted between prev and next * @prev: the left-side entry * @next: the right-side entry */ static inline void list_insert(struct list_head *p, struct list_head *prev, struct list_head *next) { next->prev = p; p->next = next; p->prev = prev; prev->next = p; } /* list_del - delete the given list entry */ static inline void list_del(struct list_head *p) { p->prev->next = p->next; p->next->prev = p->prev; } /* list_empty - returns 1 if the given list is empty */ static inline int list_empty(const struct list_head *p) { return p->next == p; } #endif /* _LIST_H */