array: Add array_bsearch function
This commit is contained in:
@@ -419,6 +419,56 @@ void array_sort(array_t *array, int (*cmp)(const void*,const void*,void*),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/** the array */
|
||||||
|
array_t *array;
|
||||||
|
/** the key */
|
||||||
|
const void *key;
|
||||||
|
/** comparison function */
|
||||||
|
int (*cmp)(const void*,const void*);
|
||||||
|
} bsearch_data_t;
|
||||||
|
|
||||||
|
static int search_elements(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
bsearch_data_t *data = (bsearch_data_t*)a;
|
||||||
|
|
||||||
|
if (data->array->esize)
|
||||||
|
{
|
||||||
|
return data->cmp(data->key, b);
|
||||||
|
}
|
||||||
|
return data->cmp(data->key, *(void**)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
int array_bsearch(array_t *array, const void *key,
|
||||||
|
int (*cmp)(const void*,const void*), void *out)
|
||||||
|
{
|
||||||
|
int idx = -1;
|
||||||
|
|
||||||
|
if (array)
|
||||||
|
{
|
||||||
|
bsearch_data_t data = {
|
||||||
|
.array = array,
|
||||||
|
.key = key,
|
||||||
|
.cmp = cmp,
|
||||||
|
};
|
||||||
|
void *start, *item;
|
||||||
|
|
||||||
|
start = array->data + get_size(array, array->head);
|
||||||
|
|
||||||
|
item = bsearch(&data, start, array->count, get_size(array, 1),
|
||||||
|
search_elements);
|
||||||
|
if (item)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
{
|
||||||
|
memcpy(out, item, get_size(array, 1));
|
||||||
|
}
|
||||||
|
idx = (item - start) / get_size(array, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
void array_invoke(array_t *array, array_callback_t cb, void *user)
|
void array_invoke(array_t *array, array_callback_t cb, void *user)
|
||||||
{
|
{
|
||||||
if (array)
|
if (array)
|
||||||
|
|||||||
@@ -185,6 +185,31 @@ bool array_remove(array_t *array, int idx, void *data);
|
|||||||
void array_sort(array_t *array, int (*cmp)(const void*,const void*,void*),
|
void array_sort(array_t *array, int (*cmp)(const void*,const void*,void*),
|
||||||
void *user);
|
void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binary search of a sorted array.
|
||||||
|
*
|
||||||
|
* The array should be sorted in ascending order according to the given
|
||||||
|
* comparison function.
|
||||||
|
*
|
||||||
|
* The comparison function must return an integer less than, equal to, or
|
||||||
|
* greater than zero if the first argument (the key) is considered to be
|
||||||
|
* respectively less than, equal to, or greater than the second.
|
||||||
|
*
|
||||||
|
* If there are multiple elements that match the key it is not specified which
|
||||||
|
* element is returned.
|
||||||
|
*
|
||||||
|
* The comparison function receives the key object and a pointer to an array
|
||||||
|
* element (esize != 0) or an actual pointer (esize = 0).
|
||||||
|
*
|
||||||
|
* @param array array to search, or NULL
|
||||||
|
* @param key key to search for
|
||||||
|
* @param cmp comparison function
|
||||||
|
* @param data data to copy element to, or NULL
|
||||||
|
* @return index of the element if found, -1 if not
|
||||||
|
*/
|
||||||
|
int array_bsearch(array_t *array, const void *key,
|
||||||
|
int (*cmp)(const void*,const void*), void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke a callback for all array members.
|
* Invoke a callback for all array members.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -359,6 +359,67 @@ START_TEST(test_sort_ptr)
|
|||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
static int comp_search_obj(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
return *(int*)a - *(int*)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(test_bsearch_obj)
|
||||||
|
{
|
||||||
|
array_t *array;
|
||||||
|
int x[] = { 3, 2, 1 };
|
||||||
|
int k, v;
|
||||||
|
|
||||||
|
array = array_create(sizeof(x[0]), 0);
|
||||||
|
array_insert(array, ARRAY_TAIL, &x[0]);
|
||||||
|
array_insert(array, ARRAY_TAIL, &x[1]);
|
||||||
|
array_insert(array, ARRAY_TAIL, &x[2]);
|
||||||
|
|
||||||
|
array_sort(array, (void*)comp_search_obj, NULL);
|
||||||
|
|
||||||
|
k = 0;
|
||||||
|
ck_assert_int_eq(array_bsearch(array, &k, comp_search_obj, &v), -1);
|
||||||
|
for (k = 1; k < 4; k++)
|
||||||
|
{
|
||||||
|
ck_assert_int_eq(array_bsearch(array, &k, comp_search_obj, &v), k-1);
|
||||||
|
ck_assert_int_eq(v, k);
|
||||||
|
}
|
||||||
|
k = 4;
|
||||||
|
ck_assert_int_eq(array_bsearch(array, &k, comp_search_obj, &v), -1);
|
||||||
|
array_destroy(array);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
static int comp_search_ptr(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
return strcmp(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(test_bsearch_ptr)
|
||||||
|
{
|
||||||
|
array_t *array;
|
||||||
|
char *x[] = {"c", "b", "a"};
|
||||||
|
char *v;
|
||||||
|
|
||||||
|
array = array_create(0, 0);
|
||||||
|
array_insert(array, ARRAY_TAIL, x[0]);
|
||||||
|
array_insert(array, ARRAY_TAIL, x[1]);
|
||||||
|
array_insert(array, ARRAY_TAIL, x[2]);
|
||||||
|
|
||||||
|
array_sort(array, (void*)comp_search_ptr, NULL);
|
||||||
|
|
||||||
|
ck_assert_int_eq(array_bsearch(array, "abc", comp_search_ptr, &v), -1);
|
||||||
|
ck_assert_int_eq(array_bsearch(array, "a", comp_search_ptr, &v), 0);
|
||||||
|
ck_assert_str_eq(v, "a");
|
||||||
|
ck_assert_int_eq(array_bsearch(array, "b", comp_search_ptr, &v), 1);
|
||||||
|
ck_assert_str_eq(v, "b");
|
||||||
|
ck_assert_int_eq(array_bsearch(array, "c", comp_search_ptr, &v), 2);
|
||||||
|
ck_assert_str_eq(v, "c");
|
||||||
|
|
||||||
|
array_destroy(array);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
static void invoke(void *data, int idx, void *user)
|
static void invoke(void *data, int idx, void *user)
|
||||||
{
|
{
|
||||||
int *y = user, *x = data;
|
int *y = user, *x = data;
|
||||||
@@ -454,6 +515,11 @@ Suite *array_suite_create()
|
|||||||
tcase_add_test(tc, test_sort_ptr);
|
tcase_add_test(tc, test_sort_ptr);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
tc = tcase_create("bsearch");
|
||||||
|
tcase_add_test(tc, test_bsearch_obj);
|
||||||
|
tcase_add_test(tc, test_bsearch_ptr);
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
tc = tcase_create("invoke");
|
tc = tcase_create("invoke");
|
||||||
tcase_add_test(tc, test_invoke);
|
tcase_add_test(tc, test_invoke);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|||||||
Reference in New Issue
Block a user