/*
 *
 * Copyright (c) Vaisala Group 2008, 2009. All rights reserved.
 *
 * The terms "Vaisala" and "Vaisala Group" are defined as
 * "Vaisala Oyj and all its subsidiaries".
 *
 */

#ifndef _DLLIST_H_
#define _DLLIST_H_

#define DLLIST_EMPTY_NEXT (NULL)
#define DLLIST_EMPTY_PREV (NULL)

struct dllist_node
{
    struct dllist_node * next;
    struct dllist_node * prev;
};

/* reference containing data node of type dnode_type */
#define  dllist_dnode(node_ptr, dnode_type, node_name)                  \
    ((dnode_type *)((uint8_t*)(node_ptr) - offsetof(dnode_type,node_name)))

static inline void  dllist_init_head(struct dllist_node * head)
{
    head->next = head;
    head->prev = head;
}

static inline void  dllist_init_node(struct dllist_node * node)
{
    node->next = DLLIST_EMPTY_NEXT;
    node->prev = DLLIST_EMPTY_PREV;
}

#define dllist_empty(head_ptr) ((head_ptr)->next == head_ptr)

static inline void  dllist_insert_after(struct dllist_node * new_node,
					struct dllist_node * old_node)
{
    struct dllist_node * prev_node = old_node;
    struct dllist_node * next_node = old_node->next;

    next_node->prev = new_node;
    new_node->next  = next_node;
    new_node->prev  = prev_node;
    prev_node->next = new_node;	
}

static inline void  dllist_insert_before(struct dllist_node * new_node,
                                         struct dllist_node * old_node)
{
    struct dllist_node * prev_node = (old_node)->prev;
    struct dllist_node * next_node = (old_node);

    next_node->prev = new_node;
    new_node->next  = next_node;
    new_node->prev  = prev_node;
    prev_node->next = new_node;	
}

static inline void  dllist_remove(struct dllist_node * node)
{
    struct dllist_node * prev = node->prev;
    struct dllist_node * next = node->next;

    next->prev = prev;
    prev->next = next;
    node->next = DLLIST_EMPTY_NEXT;
    node->prev = DLLIST_EMPTY_PREV;
}

#define dllist_for_each(node, next_node, head)          \
    for (node = (head)->next, next_node = node->next;   \
         node != (head);                                \
         node = next_node, next_node = node->next)

#define dllist_for_each_dnode(node, next_dnode, head, type, name)       \
    for (node = dllist_dnode((head)->next, type, name),                 \
             next_dnode = dllist_dnode(node->name.next,                 \
                                       type, name);                     \
         &node->name != (head);                                         \
         node = next_dnode, next_dnode =                                \
             dllist_dnode(next_dnode->name.next,                        \
                          type, name))


#endif /* _DLLIST_H_ */
