/* Macros to handle insertion, deletion, iteration, and searching for
* linked lists and arrays.
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* Parts written by Andrew Kempe and others.
* This program is free but copyrighted software; see the file COPYING for
* details.
*/
#ifndef LIST_ARRAY_H
#define LIST_ARRAY_H
/*************************************************************************/
/*************************************************************************/
/* Remove anything defined by system headers. */
#undef LIST_INSERT
#undef LIST_INSERT_ORDERED
#undef LIST_REMOVE
#undef LIST_FOREACH
#undef LIST_FOREACH_SAFE
#undef LIST_SEARCH
#undef LIST_SEARCH_SCALAR
#undef LIST_SEARCH_ORDERED
#undef LIST_SEARCH_ORDERED_SCALAR
#undef ARRAY2_EXTEND
#undef ARRAY2_INSERT
#undef ARRAY2_REMOVE
#undef ARRAY2_FOREACH
#undef ARRAY2_SEARCH
#undef ARRAY2_SEARCH_SCALAR
#undef ARRAY2_SEARCH_PLAIN_SCALAR
#undef ARRAY_EXTEND
#undef ARRAY_INSERT
#undef ARRAY_REMOVE
#undef ARRAY_FOREACH
#undef ARRAY_SEARCH
#undef ARRAY_SEARCH_SCALAR
#undef ARRAY_SEARCH_PLAIN_SCALAR
/*************************************************************************/
/* Insert `node' into the beginning of `list'. `node' and `list' must be
* simple variables (or indirections or array references).
*/
#define LIST_INSERT(node,list) \
do { \
node->next = list; \
node->prev = NULL; \
if (list) \
(list)->prev = node; \
list = node; \
} while (0)
/*************************************************************************/
/* Insert `node' into `list' so that `list' maintains its order as
* determined by the function `compare' called on `field' of each node.
* `node' and `list' must be simple variables; `field' must be a field of
* `node'; and `compare' must be a function that takes two `field's and
* returns -1, 0, or 1 indicating whether the first argument is ordered
* before, equal to, or after the second (strcmp, for example). If an
* equal node is found, `node' is inserted after it.
*/
#define LIST_INSERT_ORDERED(node,list,compare,field) \
do { \
typeof(node) ptr, prev; \
for (ptr = list, prev = NULL; ptr; prev = ptr, ptr = ptr->next) { \
if (compare(node->field, ptr->field) < 0) \
break; \
} \
node->next = ptr; \
node->prev = prev; \
if (ptr) \
ptr->prev = node; \
if (prev) \
prev->next = node; \
else \
list = node; \
} while (0)
/*************************************************************************/
/* Remove `node' from `list'. `node' and `list' must be simple variables. */
#define LIST_REMOVE(node,list) \
do { \
if (node->next) \
node->next->prev = node->prev; \
if (node->prev) \
node->prev->next = node->next; \
else \
list = node->next; \
} while (0)
/*************************************************************************/
/* Loop over every element in `list', using `iter' as the iterator. The
* macro has the same properties as a for() loop. `iter' must be a simple
* variable.
*/
#define LIST_FOREACH(iter,list) \
for (iter = (list); iter; iter = iter->next)
/*************************************************************************/
/* Iterate over `list' using an extra variable (`temp') to hold the next
* element, ensuring proper operation even when the current element is
* deleted.
*/
#define LIST_FOREACH_SAFE(iter,list,temp) \
for (iter = (list); iter && (temp = iter->next, 1); iter = temp)
/*************************************************************************/
/* Search `list' for a node with `field' equal to `target' (as evaluated by
* `compare') and place a pointer to the node found in `result' (or NULL if
* none found). `result' must be a simple variable; `compare' must be a
* strcmp()-like function (see LIST_INSERT_ORDERED).
*/
#define LIST_SEARCH(list,field,target,compare,result) \
do { \
LIST_FOREACH (result, list) { \
if (compare(result->field, target) == 0) \
break; \
} \
} while (0)
/*************************************************************************/
/* Search `list' as LIST_SEARCH does, but for a scalar value. */
#define LIST_SEARCH_SCALAR(list,field,target,result) \
do { \
LIST_FOREACH (result, list) { \
if (result->field == target) \
break; \
} \
} while (0)
/*************************************************************************/
/* Search `list' as LIST_SEARCH does, but for a list known to be ordered. */
#define LIST_SEARCH_ORDERED(list,field,target,compare,result) \
do { \
LIST_FOREACH (result, list) { \
int i = compare(result->field, target); \
if (i > 0) \
result = NULL; \
if (i >= 0) \
break; \
} \
} while (0)
/*************************************************************************/
/* Search `list' as LIST_SEARCH_ORDERED does, but for a scalar value. */
#define LIST_SEARCH_ORDERED_SCALAR(list,field,target,result) \
do { \
LIST_FOREACH (result, list) { \
int i = result->field - target; \
if (i > 0) \
result = NULL; \
if (i >= 0) \
break; \
} \
} while (0)
/*************************************************************************/
/*************************************************************************/
/* Extend a variable-length array by one entry. `size' is the variable
* which holds the current length of `array'.
*/
#define ARRAY2_EXTEND(array,size) \
do { \
(size)++; \
array = srealloc(array, sizeof(*array) * size); \
} while (0)
/*************************************************************************/
/* Insert a slot at the given position in a variable-length array. */
#define ARRAY2_INSERT(array,size,index) \
do { \
(size)++; \
array = srealloc(array, sizeof(*array) * size); \
if (index < size-1) \
memmove(&array[index+1], &array[index], \
sizeof(*array) * ((size-1)-index)); \
} while (0)
/*************************************************************************/
/* Delete entry number `index' from a variable-length array. */
#define ARRAY2_REMOVE(array,size,index) \
do { \
(size)--; \
if (index < size) \
memmove(&array[index], &array[index]+1, sizeof(*array)*(size-index));\
array = srealloc(array, sizeof(*array) * size); \
} while (0)
/*************************************************************************/
/* Loop over every element in a variable-length array. */
#define ARRAY2_FOREACH(iter,array,size) \
for (iter = 0; iter < size; iter++)
/*************************************************************************/
/* Search a variable-length array for a value. Operates like LIST_SEARCH.
* `result' must be an integer variable. If nothing is found, `result' will
* be set equal to `size'.
*/
#define ARRAY2_SEARCH(array,size,field,target,compare,result) \
do { \
ARRAY2_FOREACH (result, array, size) { \
if (compare(array[result].field, target) == 0) \
break; \
} \
} while (0)
/*************************************************************************/
/* Search a variable-length array for a value. The array does not have
* fields.
*/
#define ARRAY2_SEARCH_PLAIN(array,size,target,compare,result) \
do { \
ARRAY2_FOREACH (result, array, size) { \
if (compare(array[result], target) == 0) \
break; \
} \
} while (0)
/*************************************************************************/
/* Search a variable-length array for a scalar value. */
#define ARRAY2_SEARCH_SCALAR(array,size,field,target,result) \
do { \
ARRAY2_FOREACH (result, array, size) { \
if (array[result].field == target) \
break; \
} \
} while (0)
/*************************************************************************/
/* Search a variable-length array for a scalar value. The array does not
* have fields. */
#define ARRAY2_SEARCH_PLAIN_SCALAR(array,size,target,result) \
do { \
ARRAY2_FOREACH (result, array, size) { \
if (array[result] == target) \
break; \
} \
} while (0)
/*************************************************************************/
/*************************************************************************/
/* Perform the ARRAY2_* actions on an array `array' whose size is stored in
* `array_count'. */
#define ARRAY_EXTEND(array) ARRAY2_EXTEND(array,array##_count)
#define ARRAY_INSERT(array,index) ARRAY2_INSERT(array,array##_count,index)
#define ARRAY_REMOVE(array,index) ARRAY2_REMOVE(array,array##_count,index)
#define ARRAY_FOREACH(iter,array) ARRAY2_FOREACH(iter,array,array##_count)
#define ARRAY_SEARCH(array,field,target,compare,result) \
ARRAY2_SEARCH(array,array##_count,field,target,compare,result)
#define ARRAY_SEARCH_PLAIN(array,target,compare,result) \
ARRAY2_SEARCH_PLAIN(array,array##_count,target,compare,result)
#define ARRAY_SEARCH_SCALAR(array,field,target,result) \
ARRAY2_SEARCH_SCALAR(array,array##_count,field,target,result)
#define ARRAY_SEARCH_PLAIN_SCALAR(array,target,result) \
ARRAY2_SEARCH_PLAIN_SCALAR(array,array##_count,target,result)
/*************************************************************************/
/*************************************************************************/
#endif /* LIST_ARRAY_H */
syntax highlighted by Code2HTML, v. 0.9.1