/*
**  OSSP al -- Assembly Line
**  Copyright (c) 2002-2005 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2002-2005 Cable & Wireless <http://www.cw.com/>
**  Copyright (c) 2002-2005 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2002-2005 Michael van Elst <mlelstv@serpens.de>
**
**  This file is part of OSSP al, an abstract datatype of a data buffer
**  that can assemble, move and truncate data but avoids actual copying.
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  list.h: generic double-linked list macros
*/

#ifndef __LIST_H__
#define __LIST_H__

#define LIST(elem) \
    struct { elem *head, *tail; }
#define NODE(elem) \
    struct { elem *next, *prev; }

#define HEAD(q,l)       ((q)->l.head)
#define TAIL(q,l)       ((q)->l.tail)
#define NEXT(n,l)       ((n)->l.next)
#define PREV(n,l)       ((n)->l.prev)

#define ISEMPTY(q,l)    (HEAD(q,l) == NULL)

#define LISTINIT(q,l) \
do { \
    HEAD(q,l) = NULL; \
    TAIL(q,l) = NULL;  \
} while(0)

#define NODEINIT(n,l) \
do { \
    NEXT(n,l) = NULL; \
    PREV(n,l) = NULL; \
} while(0)

#define ADDTAIL2(q,l,n1,n2) \
do { \
    if (TAIL(q,l)) { \
        NEXT(TAIL(q,l),l) = (n1); \
        PREV(n1,l) = TAIL(q,l); \
    } else { \
        HEAD(q,l) = (n1); \
        PREV(n1,l) = NULL; \
    } \
    TAIL(q,l) = (n2); \
    NEXT(n2,l) = NULL; \
} while (0)
#define ADDTAIL(q,l,n) ADDTAIL2(q,l,n,n)

#define ADDHEAD2(q,l,n1,n2) \
do { \
    if (HEAD(q,l)) { \
        PREV(HEAD(q,l),l) = (n2); \
        NEXT(n2,l) = HEAD(q,l); \
    } else { \
        TAIL(q,l) = (n2); \
        NEXT(n2,l) = NULL; \
    } \
    HEAD(q,l) = (n1); \
    PREV(n1,l) = NULL; \
} while (0)
#define ADDHEAD(q,l,n) ADDHEAD2(q,l,n,n)

#define REMHEAD(q,l,n) \
do { \
    (n) = HEAD(q,l); \
    if (n) { \
        HEAD(q,l) = NEXT(n,l); \
        if (HEAD(q,l)) \
            PREV(HEAD(q,l),l) = NULL; \
        else \
            TAIL(q,l) = NULL; \
    } \
} while(0)

#define REMTAIL(q,l,n) \
do { \
    (n) = TAIL(q,l); \
    if (n) { \
        TAIL(q,l) = PREV(n,l); \
        if (TAIL(q,l)) \
            NEXT(TAIL(q,l),l) = NULL; \
        else \
            HEAD(q,l) = NULL; \
    } \
} while(0)

#define REMOVE2(q,l,n1,n2) \
do { \
    if (PREV(n1,l)) \
        NEXT(PREV(n1,l),l) = NEXT(n2,l); \
    else \
        HEAD(q,l) = NEXT(n2,l); \
    if (NEXT(n2,l)) \
        PREV(NEXT(n2,l),l) = PREV(n1,l); \
    else \
        TAIL(q,l) = PREV(n1,l); \
    NEXT(n2,l) = NULL; \
    PREV(n1,l) = NULL; \
} while (0)
#define REMOVE(q,l,n) REMOVE2(q,l,n,n)

#define INSERT2(q,l,i,n1,n2) \
do { \
    if (PREV(i,l)) { \
        NEXT(PREV(i,l),l) = (n1); \
    } else { \
        HEAD(q,l) = (n1); \
    } \
    PREV(n1,l) = PREV(i,l); \
    PREV(i,l) = (n2); \
    NEXT(n2,l) = (i); \
} while (0)
#define INSERT(q,l,i,n) INSERT2(q,l,i,n,n)

#define APPENDLIST(q1,l,q2) \
do { \
    if (TAIL(q1,l)) { \
        NEXT(TAIL(q1,l),l) = HEAD(q2,l); \
        PREV(HEAD(q2,l),l) = TAIL(q1,l); \
    } else { \
        HEAD(q1,l) = HEAD(q2,l); \
    } \
    TAIL(q1,l) = TAIL(q2,l); \
    LISTINIT(q2,l); \
} while(0)

#define INSERTLIST(q1,l,i,q2) \
do { \
    if (PREV(i,l)) { \
        NEXT(PREV(i,l),l) = HEAD(q2,l); \
    } else { \
        HEAD(q1,l) = HEAD(q2,l); \
    } \
    PREV(HEAD(q2,l),l) = PREV(i,l); \
    NEXT(TAIL(q2,l),l) = (i); \
    PREV(i,l) = TAIL(q2,l); \
    LISTINIT(q2,l); \
} while(0)

#define FOREACH(q,l,n)    for (n = HEAD(q,l); n; n = NEXT(n,l))
#define FOREACHR(q,l,n)   for (n = TAIL(q,l); n; n = PREV(n,l))
#define FOREACHD(q,l,n,r) for (n = TAIL(q,l); n && (r = PREV(n,l), 1); n = r)

#endif /* __LIST_H__ */

