Blame usr/lib/common/list.h

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