/* * COPYRIGHT (c) International Business Machines Corp. 2005-2017 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* * Very small linked list implementation. * * For simplicity and portability it doesn't use GCC extensions and sticks with * C89. That means there's no hidden variable declaration or type inference * inside the macros. */ #ifndef _LIST_H_ #define _LIST_H_ #include /* for offsetof */ /* * Typedefs for lists and list entries. * * List entry should be defined as a member in an application-specific * structure. */ typedef struct _list list_t; typedef struct _list_entry list_entry_t; struct _list { list_entry_t *head; list_entry_t *tail; }; struct _list_entry { list_entry_t *next; list_entry_t *prev; list_t *list; }; /* A helper macro */ #ifndef container_of #define container_of(_pt, _type, _field) \ ((_type *) (!(_pt) ? NULL : (((char *) (_pt)) - offsetof(_type, _field)))) #endif /* * Macro to iterate over a list. * * It can *NOT* be used to remove entries while iterating. * */ #define for_each_list_entry(_head, _type, _var, _field) \ for (_var = container_of((_head)->head, _type, _field); \ (_var) && &((_var)->_field); \ _var = container_of((_var)->_field.next, _type, _field)) /* * Similar to for_each_list_entry but it's possible to remove an entry while * iterating. * * It uses an additional list_entry_t* to hold the value of the next element. */ #define for_each_list_entry_safe(_head, _type, _var, _field, _next) \ for (_var = container_of((_head)->head, _type, _field); \ (_var) && &((_var)->_field) && \ ((_next = (_var)->_field.next) || 1); \ _var = container_of(_next, _type, _field)) /* * Assignment initialization macro. */ #define LIST_INIT() \ { NULL, NULL } /* * Initialize a list. */ static inline void list_init(list_t *list) { list->head = list->tail = NULL; } static inline int list_is_empty(list_t *list) { return (list->head == NULL); } /* * Insert a element at the head. */ static inline void list_insert_head(list_t *list, list_entry_t *new) { if (!list->head) { new->next = new->prev = NULL; list->head = list->tail = new; } else { new->prev = NULL; new->next = list->head; list->head->prev = new; list->head = new; } new->list = list; } /* * Insert a element at the end. * (currently unused) static inline void list_insert_tail(list_t *list, list_entry_t *new) { if (!list->tail) { new->next = new->prev = NULL; list->head = list->tail = new; } else { new->next = NULL; new->prev = list->tail; list->tail->next = new; list->tail = new; } new->list = list; } */ /* * Remove an element. */ static inline void list_remove(list_entry_t *entry) { list_t *list = entry->list; if (list->head == entry) list->head = entry->next; if (list->tail == entry) list->tail = entry->prev; if (entry->next) entry->next->prev = entry->prev; if (entry->prev) entry->prev->next = entry->next; } #endif