terom@35: #ifndef CHAIN_H terom@35: #define CHAIN_H terom@35: terom@35: /** terom@87: * @file terom@35: * terom@171: * Defines a brain-dead auto-allocated linked list for simple uses. terom@35: */ terom@35: #include "error.h" terom@35: #include terom@171: #include terom@171: #include terom@35: terom@35: /** terom@171: * Header entry to embed a chain_item terom@35: */ terom@171: #define CHAIN_ITEM_HEADER(type) TAILQ_ENTRY(type) _chain_list terom@35: terom@35: /** terom@171: * Header entry to embed a chain_head terom@35: */ terom@171: #define CHAIN_HEAD_TYPE(head_type, item_type) \ terom@171: struct head_type { \ terom@171: TAILQ_HEAD(head_type ## _head, item_type) head; \ terom@171: } terom@35: terom@35: /** terom@171: * Generic chain_head type terom@69: */ terom@171: struct _chain_item { terom@171: TAILQ_ENTRY(_chain_item) _chain_list; terom@171: }; terom@171: terom@171: TAILQ_HEAD(_chain_head, _chain_item); terom@69: terom@69: /** terom@171: * Cast to a chain_item terom@35: */ terom@171: #define CHAIN_CAST_ITEM(item_ptr) &(item_ptr)->_chain_list terom@171: terom@171: /** terom@171: * Ref the head struct from the given chain_head terom@171: */ terom@171: #define CHAIN_DEREF_HEAD(head_ptr) &(head_ptr)->head terom@171: terom@171: /** terom@171: * Cast to a generic _chain_head terom@171: */ terom@171: #define CHAIN_HEAD_GENERIC(head_ptr) (struct _chain_head *) CHAIN_DEREF_HEAD(head_ptr) terom@171: terom@171: /** terom@171: * Evaluates to the type of the given CHAIN_HEAD terom@171: */ terom@171: #define CHAIN_TYPE(head_ptr) typeof (*TAILQ_FIRST(CHAIN_DEREF_HEAD(head_ptr))) terom@171: terom@171: terom@171: terom@171: /** terom@171: * Initialize a chain_head to be empty terom@171: */ terom@171: #define CHAIN_INIT(head_ptr) TAILQ_INIT(CHAIN_DEREF_HEAD(head_ptr)) terom@171: terom@171: terom@171: /** terom@171: * Return the first item in the chain as a pointer of the correct type terom@171: */ terom@171: #define CHAIN_FIRST(head_ptr) TAILQ_FIRST(CHAIN_DEREF_HEAD(head_ptr)) terom@171: terom@171: /** terom@171: * Return the item after the given item terom@171: */ terom@171: #define CHAIN_NEXT(item_ptr) TAILQ_NEXT(item_ptr, _chain_list) terom@171: terom@171: terom@171: terom@171: /** terom@171: * Allocate a new chain_item of the given type, adding it to the beginning of the list, and returning a calloc'd terom@171: * struct of the given type. terom@171: */ terom@171: #define CHAIN_ADD_HEAD(head_ptr) (CHAIN_TYPE(head_ptr) *) _chain_add(CHAIN_HEAD_GENERIC(head_ptr), false, sizeof (*CHAIN_TYPE(head_ptr))) terom@171: terom@171: /** terom@171: * Same as CHAIN_ADD_HEAD, except this adds the new item to the end of the list. terom@171: */ terom@171: #define CHAIN_ADD_TAIL(head_ptr) (CHAIN_TYPE(head_ptr) *) _chain_add(CHAIN_HEAD_GENERIC(head_ptr), true, sizeof (CHAIN_TYPE(head_ptr))) terom@171: terom@171: terom@171: terom@171: /** terom@171: * Iterate over the items in a chain terom@171: */ terom@171: #define CHAIN_FOREACH(head_ptr, item_ptr) TAILQ_FOREACH(item_ptr, CHAIN_DEREF_HEAD(head_ptr), _chain_list) terom@171: terom@171: /** terom@171: * Safely iterate over the items in a chain, such that the iterated-over item can be removed without breaking the chain terom@171: */ terom@171: #define CHAIN_FOREACH_SAFE(head_ptr, item_ptr) \ terom@171: for ( \ terom@171: typeof (item_ptr) _chain_next = CHAIN_FIRST(head_ptr); \ terom@171: ((void) ((item_ptr = _chain_next) && (_chain_next = CHAIN_NEXT(_chain_next)))), item_ptr; \ terom@171: (void) 0 \ terom@171: ) terom@171: terom@171: terom@171: /** terom@171: * Remove an item from the list and free it. terom@171: */ terom@171: #define CHAIN_DELETE(head_ptr, item_ptr) \ terom@171: do { \ terom@171: TAILQ_REMOVE(CHAIN_DEREF_HEAD(head_ptr), item_ptr, _chain_list); \ terom@171: free(item_ptr); \ terom@171: } while (0); terom@171: terom@171: /** terom@171: * Delete the items from the chain for which the given predicate matches terom@171: */ terom@171: #define CHAIN_DELETE_WHICH(head_ptr, item_ptr, predicate) \ terom@171: do { \ terom@171: CHAIN_FOREACH_SAFE(head_ptr, item_ptr) \ terom@171: if (predicate) \ terom@171: CHAIN_DELETE(head_ptr, item_ptr); \ terom@171: } while (0) terom@171: terom@171: /** terom@171: * Delete all items from the chain terom@171: */ terom@171: #define CHAIN_CLEAR(head_ptr) \ terom@171: do { \ terom@171: CHAIN_TYPE(head_ptr) *_chain_item; \ terom@171: CHAIN_FOREACH_SAFE(head_ptr, _chain_item) \ terom@171: free(_chain_item); \ terom@171: } while (0); terom@171: terom@171: terom@171: terom@171: void *_chain_add (struct _chain_head *head, bool tail, size_t size); terom@35: terom@35: #endif