/*
 * 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 <stddef.h>             /* 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
