// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM
// Exceptions. See
// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license
// information.
//
// Significant parts of this file are derived from cloudabi-utils. See
// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE
// for license information.
//
// The upstream file contains the following copyright notice:
//
// Copyright (c) 2016 Nuxi, https://nuxi.nl/

#ifndef QUEUE_H
#define QUEUE_H

// LIST: Double-linked list.

#define LIST_HEAD(name, type) \
    struct name {             \
        struct type *l_first; \
    }

/* clang-format off */
#define LIST_HEAD_INITIALIZER(head) \
    { NULL }
/* clang-format on */

#define LIST_ENTRY(type)      \
    struct {                  \
        struct type *l_next;  \
        struct type **l_prev; \
    }

#define LIST_FOREACH(var, head, field) \
    for ((var) = (head)->l_first; (var) != NULL; (var) = (var)->field.l_next)

#define LIST_INIT(head)         \
    do {                        \
        (head)->l_first = NULL; \
    } while (0)

#define LIST_INSERT_HEAD(head, element, field)                        \
    do {                                                              \
        (element)->field.l_next = (head)->l_first;                    \
        if ((head)->l_first != NULL)                                  \
            (head)->l_first->field.l_prev = &(element)->field.l_next; \
        (head)->l_first = (element);                                  \
        (element)->field.l_prev = &(head)->l_first;                   \
    } while (0)

#define LIST_REMOVE(element, field)                                          \
    do {                                                                     \
        if ((element)->field.l_next != NULL)                                 \
            (element)->field.l_next->field.l_prev = (element)->field.l_prev; \
        *(element)->field.l_prev = (element)->field.l_next;                  \
    } while (0)

// TAILQ: Double-linked list with tail pointer.

#define TAILQ_HEAD(name, type) \
    struct name {              \
        struct type *t_first;  \
        struct type **t_last;  \
    }

#define TAILQ_ENTRY(type)     \
    struct {                  \
        struct type *t_next;  \
        struct type **t_prev; \
    }

#define TAILQ_EMPTY(head) ((head)->t_first == NULL)
#define TAILQ_FIRST(head) ((head)->t_first)
#define TAILQ_FOREACH(var, head, field) \
    for ((var) = (head)->t_first; (var) != NULL; (var) = (var)->field.t_next)
#define TAILQ_INIT(head)                   \
    do {                                   \
        (head)->t_first = NULL;            \
        (head)->t_last = &(head)->t_first; \
    } while (0)
#define TAILQ_INSERT_TAIL(head, elm, field)    \
    do {                                       \
        (elm)->field.t_next = NULL;            \
        (elm)->field.t_prev = (head)->t_last;  \
        *(head)->t_last = (elm);               \
        (head)->t_last = &(elm)->field.t_next; \
    } while (0)
#define TAILQ_REMOVE(head, element, field)                                   \
    do {                                                                     \
        if ((element)->field.t_next != NULL)                                 \
            (element)->field.t_next->field.t_prev = (element)->field.t_prev; \
        else                                                                 \
            (head)->t_last = (element)->field.t_prev;                        \
        *(element)->field.t_prev = (element)->field.t_next;                  \
    } while (0)

#endif
