/* Macros to handle insertion, deletion, iteration, and searching for * linked lists and arrays. * * IRC Services is copyright (c) 1996-2007 Andrew Church. * E-mail: * 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 */