src/chain.h
author Tero Marttila <terom@fixme.fi>
Thu, 28 May 2009 01:17:36 +0300
branchnew-lib-errors
changeset 219 cefec18b8268
parent 171 b54f393c3df0
permissions -rw-r--r--
some of the lib/transport stuff compiles
#ifndef CHAIN_H
#define CHAIN_H

/**
 * @file
 *
 * Defines a brain-dead auto-allocated linked list for simple uses.
 */
#include "error.h"
#include <sys/queue.h>
#include <stdlib.h>
#include <stdbool.h>

/**
 * Header entry to embed a chain_item
 */
#define CHAIN_ITEM_HEADER(type) TAILQ_ENTRY(type) _chain_list

/**
 * Header entry to embed a chain_head
 */
#define CHAIN_HEAD_TYPE(head_type, item_type) \
    struct head_type {  \
        TAILQ_HEAD(head_type ## _head, item_type) head;  \
    }

/**
 * Generic chain_head type
 */
struct _chain_item {
   TAILQ_ENTRY(_chain_item) _chain_list;
};

TAILQ_HEAD(_chain_head, _chain_item);

/**
 * Cast to a chain_item
 */
#define CHAIN_CAST_ITEM(item_ptr) &(item_ptr)->_chain_list

/**
 * Ref the head struct from the given chain_head
 */
#define CHAIN_DEREF_HEAD(head_ptr) &(head_ptr)->head

/**
 * Cast to a generic _chain_head
 */
#define CHAIN_HEAD_GENERIC(head_ptr) (struct _chain_head *) CHAIN_DEREF_HEAD(head_ptr)

/**
 * Evaluates to the type of the given CHAIN_HEAD
 */
#define CHAIN_TYPE(head_ptr) typeof (*TAILQ_FIRST(CHAIN_DEREF_HEAD(head_ptr)))



/**
 * Initialize a chain_head to be empty
 */
#define CHAIN_INIT(head_ptr) TAILQ_INIT(CHAIN_DEREF_HEAD(head_ptr))


/**
 * Return the first item in the chain as a pointer of the correct type
 */
#define CHAIN_FIRST(head_ptr) TAILQ_FIRST(CHAIN_DEREF_HEAD(head_ptr))

/**
 * Return the item after the given item
 */
#define CHAIN_NEXT(item_ptr) TAILQ_NEXT(item_ptr, _chain_list)



/**
 * Allocate a new chain_item of the given type, adding it to the beginning of the list, and returning a calloc'd
 * struct of the given type.
 */
#define CHAIN_ADD_HEAD(head_ptr) (CHAIN_TYPE(head_ptr) *) _chain_add(CHAIN_HEAD_GENERIC(head_ptr), false, sizeof (*CHAIN_TYPE(head_ptr)))

/**
 * Same as CHAIN_ADD_HEAD, except this adds the new item to the end of the list.
 */
#define CHAIN_ADD_TAIL(head_ptr) (CHAIN_TYPE(head_ptr) *) _chain_add(CHAIN_HEAD_GENERIC(head_ptr), true,  sizeof (CHAIN_TYPE(head_ptr)))



/**
 * Iterate over the items in a chain
 */
#define CHAIN_FOREACH(head_ptr, item_ptr) TAILQ_FOREACH(item_ptr, CHAIN_DEREF_HEAD(head_ptr), _chain_list)

/**
 * Safely iterate over the items in a chain, such that the iterated-over item can be removed without breaking the chain
 */
#define CHAIN_FOREACH_SAFE(head_ptr, item_ptr) \
    for (   \
            typeof (item_ptr) _chain_next = CHAIN_FIRST(head_ptr); \
            ((void) ((item_ptr = _chain_next) && (_chain_next = CHAIN_NEXT(_chain_next)))), item_ptr; \
            (void) 0  \
    )


/**
 * Remove an item from the list and free it.
 */
#define CHAIN_DELETE(head_ptr, item_ptr) \
    do {    \
        TAILQ_REMOVE(CHAIN_DEREF_HEAD(head_ptr), item_ptr, _chain_list);    \
        free(item_ptr); \
    } while (0);

/**
 * Delete the items from the chain for which the given predicate matches
 */
#define CHAIN_DELETE_WHICH(head_ptr, item_ptr, predicate) \
    do {    \
        CHAIN_FOREACH_SAFE(head_ptr, item_ptr)  \
            if (predicate)  \
                CHAIN_DELETE(head_ptr, item_ptr);   \
    } while (0)

/**
 * Delete all items from the chain
 */
#define CHAIN_CLEAR(head_ptr) \
    do {    \
        CHAIN_TYPE(head_ptr) *_chain_item;   \
        CHAIN_FOREACH_SAFE(head_ptr, _chain_item)   \
           free(_chain_item);   \
    } while (0);



void *_chain_add (struct _chain_head *head, bool tail, size_t size);

#endif