#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