I am working on some httpd changes/features/ideas and have multiple needs to find items in an array. In httpd, we currently have these:
AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array, const char *s, int start); AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array, const char *s); In my use cases, the search may often be strings, but not always, so I thought that maybe APR could/should provide something more generic. The above functions could then be rewritten to use this new function. Here are my thoughts: 1. The search item (needle) can be anything rather than just a string as above. 2. The caller provides a callback that compares the values to needle in the same way strcmp()/strcasecmp() do. That is, 0 means "equal". In fact, strcmp()/strcasecmp() can -- and probably often will -- be used as the callback for strings. 3. A start (input) and index (output) parameter can be used to iterate and find all occurrences. What do others think? Is there value in this, or is it just me? I'm thinking something like this: diff -r 335976d9e7cb include/apr_tables.h --- a/include/apr_tables.h Wed Apr 04 16:41:28 2018 +0000 +++ b/include/apr_tables.h Thu Apr 26 19:07:44 2018 -0500 @@ -223,6 +223,40 @@ const char sep); /** + * Declaration prototype for the comparison callback function of + * apr_array_find(). + * @param x The first item to compare + * @param y The second item to compare + * @return 0 if the items are "equal" (whatever "equal" means in the context of + * the apr_array_find() call) + * @see apr_array_find + */ +typedef int (apr_array_find_comparison_callback_fn_t)(const void *x, const void *y); + +/** + * Find an element in an array by using a callback function for comparison. + * Existing functions such as strcmp() and strcasecmp() or custom callbacks can + * be used. Finding multiple occurrences of an item can be accomplished by using + * the start and index parameters in successive calls. + * @param arr The array to search + * @param needle The value for which to search + * @param comp The comparison callback function + * @param start The index in the array at which the search should begin + * @param index If not NULL, will contain the index of the found item's offset + * within the array upon return; if the item is not found, this value is + * untouched (check for a return of NULL) + * @return The matching item from the array + * @remark The return value of this function should be used to test for success + * (finding the value) rather than the index parameter which is only + * modified if the value is found. + */ +APR_DECLARE(void *) apr_array_find(apr_array_header_t *arr, + const void *needle, + apr_array_find_comparison_callback_fn_t *comp, + int start, + int *index); + +/** * Make a new table. * @param p The pool to allocate the pool out of * @param nelts The number of elements in the initial table. diff -r 335976d9e7cb tables/apr_tables.c --- a/tables/apr_tables.c Wed Apr 04 16:41:28 2018 +0000 +++ b/tables/apr_tables.c Thu Apr 26 19:07:44 2018 -0500 @@ -281,6 +281,33 @@ return res; } +APR_DECLARE(void *) apr_array_find(apr_array_header_t *arr, + const void *needle, + apr_array_find_comparison_callback_fn_t *comp, + int start, + int *index) +{ + int i; + + if (!arr || !needle || !comp || (start < 0)) { + return NULL; + } + + for (i = start; (i < arr->nelts) && comp(needle, *(void **)(arr->elts + (arr->elt_size * i))); i++) { + /* empty */ + } + + if (i < arr->nelts) { + if (index) { + *index = i; + } + + return *(void **)(arr->elts + (arr->elt_size * i)); + } + + return NULL; +} + /***************************************************************** *