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