Commit e7519047 authored by David Gibson's avatar David Gibson Committed by Rusty Russell

asearch: Add context pointer to asearch comparison callback

asearch, like the standard library bsearch, takes a comparison callback.
Like bsearch() that callback doesn't include a user supplied context
pointer.  As well as being generally limiting, that makes the comparison
functions used by asearch gratuitously different from those used by the
asort module.

This patch alters this.  Note that this is an incompatible change to the
asearch interface.  I think this is worth it to correct the oversight, but
others might disagree.  At present the only user within ccan is ntdb, which
is corrected to match.

This means actually supplying a binary search implementation, rather than
relying on bsearch() from the standard library.  We follow the lead of the
asort module and steal^H^H^H^H^Hadapt the implementation from glibc.
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 8ad4e453
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* #include <stdio.h> * #include <stdio.h>
* #include <string.h> * #include <string.h>
* *
* static int cmp(const char *key, char *const *elem) * static int cmp(const char *key, char *const *elem, void *ctx)
* { * {
* return strcmp(key, *elem); * return strcmp(key, *elem);
* } * }
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
* exit(1); * exit(1);
* } * }
* *
* p = asearch(argv[1], &argv[2], argc-2, cmp); * p = asearch(argv[1], &argv[2], argc-2, cmp, NULL);
* if (!p) { * if (!p) {
* printf("Not found!\n"); * printf("Not found!\n");
* return 1; * return 1;
......
#include <ccan/asearch/asearch.h>
#include <stddef.h>
/* Steal glibc's code. */
/* Perform binary search - inline version.
Copyright (C) 1991-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
void *
_asearch (const void *__key, const void *__base, size_t __nmemb, size_t __size,
asearch_cmp __compar, void *ctx)
{
size_t __l, __u, __idx;
const void *__p;
int __comparison;
__l = 0;
__u = __nmemb;
while (__l < __u)
{
__idx = (__l + __u) / 2;
__p = (void *) (((const char *) __base) + (__idx * __size));
__comparison = (*__compar) (__key, __p, ctx);
if (__comparison < 0)
__u = __idx;
else if (__comparison > 0)
__l = __idx + 1;
else
return (void *) __p;
}
return NULL;
}
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <ccan/typesafe_cb/typesafe_cb.h> #include <ccan/typesafe_cb/typesafe_cb.h>
typedef int (*asearch_cmp)(const void *, const void *, void *);
/** /**
* asearch - search an array of elements * asearch - search an array of elements
* @key: pointer to item being searched for * @key: pointer to item being searched for
...@@ -22,17 +24,22 @@ ...@@ -22,17 +24,22 @@
* the same comparison function for both sort() and asearch(). * the same comparison function for both sort() and asearch().
*/ */
#if HAVE_TYPEOF #if HAVE_TYPEOF
#define asearch(key, base, num, cmp) \ #define asearch(key, base, num, cmp, ctx) \
((__typeof__(*(base))*)(bsearch((key), (base), (num), sizeof(*(base)), \ ((__typeof__(*(base))*)(_asearch((key), (base), (num), sizeof(*(base)), \
typesafe_cb_cast(int (*)(const void *, const void *), \ typesafe_cb_cast(asearch_cmp, \
int (*)(const __typeof__(*(key)) *, \ int (*)(const __typeof__(*(key)) *, \
const __typeof__(*(base)) *), \ const __typeof__(*(base)) *, \
(cmp))))) __typeof__(*(ctx)) *), \
(cmp)), (ctx))))
#else #else
#define asearch(key, base, num, cmp) \ #define asearch(key, base, num, cmp, ctx) \
(bsearch((key), (base), (num), sizeof(*(base)), \ (_asearch((key), (base), (num), sizeof(*(base)), \
(int (*)(const void *, const void *))(cmp))) (int (*)(const void *, const void *, void *))(cmp), (ctx)))
#endif #endif
void *_asearch(const void *key, const void *base,
size_t nmemb, size_t size,
asearch_cmp compar, void *ctx);
#endif /* CCAN_ASEARCH_H */ #endif /* CCAN_ASEARCH_H */
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
#include <ccan/array_size/array_size.h> #include <ccan/array_size/array_size.h>
#include <string.h> #include <string.h>
static int cmp(const char *key, const char *const *elem) #include <ccan/asearch/asearch.c>
static int cmp(const char *key, const char *const *elem, void *ctx)
{ {
return strcmp(key, *elem); return strcmp(key, *elem);
} }
...@@ -20,6 +22,6 @@ int main(void) ...@@ -20,6 +22,6 @@ int main(void)
#else #else
const char **p; const char **p;
#endif #endif
p = asearch(key, elems, ARRAY_SIZE(elems), cmp); p = asearch(key, elems, ARRAY_SIZE(elems), cmp, NULL);
return p ? 0 : 1; return p ? 0 : 1;
} }
#include <ccan/asearch/asearch.h> #include <ccan/asearch/asearch.h>
static int cmp(const char *key, char *const *elem) #include <ccan/asearch/asearch.c>
static int cmp(const char *key, char *const *elem, void *ctx)
{ {
return 0; return 0;
} }
...@@ -17,6 +19,6 @@ int main(int argc, char **argv) ...@@ -17,6 +19,6 @@ int main(int argc, char **argv)
#else #else
char **p; char **p;
#endif #endif
p = asearch(key, argv+1, argc-1, cmp); p = asearch(key, argv+1, argc-1, cmp, NULL);
return p ? 0 : 1; return p ? 0 : 1;
} }
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
#include <ccan/tap/tap.h> #include <ccan/tap/tap.h>
#include <stdlib.h> #include <stdlib.h>
static int cmp(const int *key, const char *const *elem) #include <ccan/asearch/asearch.c>
static int cmp(const int *key, const char *const *elem, void *ctx)
{ {
return *key - atoi(*elem); return *key - atoi(*elem);
} }
...@@ -15,7 +17,7 @@ int main(void) ...@@ -15,7 +17,7 @@ int main(void)
const char **p; const char **p;
plan_tests(1); plan_tests(1);
p = asearch(&key, args, ARRAY_SIZE(args), cmp); p = asearch(&key, args, ARRAY_SIZE(args), cmp, NULL);
ok1(p == &args[2]); ok1(p == &args[2]);
return exit_status(); return exit_status();
......
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
#include <ccan/tap/tap.h> #include <ccan/tap/tap.h>
#include <limits.h> #include <limits.h>
static int test_cmp(const int *key, const int *elt) #include <ccan/asearch/asearch.c>
static int test_cmp(const int *key, const int *elt, void *ctx)
{ {
if (*key < *elt) if (*key < *elt)
return -1; return -1;
...@@ -23,12 +25,14 @@ int main(void) ...@@ -23,12 +25,14 @@ int main(void)
for (start = 0; start < ARRAY_SIZE(arr); start++) { for (start = 0; start < ARRAY_SIZE(arr); start++) {
for (num = 0; num < ARRAY_SIZE(arr) - start; num++) { for (num = 0; num < ARRAY_SIZE(arr) - start; num++) {
key = 7; key = 7;
ok1(asearch(&key, &arr[start], num, test_cmp) == NULL); ok1(asearch(&key, &arr[start], num, test_cmp,
NULL) == NULL);
total++; total++;
for (i = start; i < start+num; i++) { for (i = start; i < start+num; i++) {
const int *ret; const int *ret;
key = arr[i]; key = arr[i];
ret = asearch(&key, &arr[start], num, test_cmp); ret = asearch(&key, &arr[start], num,
test_cmp, NULL);
ok1(ret); ok1(ret);
ok1(ret && *ret == key); ok1(ret && *ret == key);
total++; total++;
......
...@@ -114,7 +114,7 @@ static enum NTDB_ERROR check_header(struct ntdb_context *ntdb, ...@@ -114,7 +114,7 @@ static enum NTDB_ERROR check_header(struct ntdb_context *ntdb,
return NTDB_SUCCESS; return NTDB_SUCCESS;
} }
static int off_cmp(const ntdb_off_t *a, const ntdb_off_t *b) static int off_cmp(const ntdb_off_t *a, const ntdb_off_t *b, void *ctx)
{ {
/* Can overflow an int. */ /* Can overflow an int. */
return *a > *b ? 1 return *a > *b ? 1
...@@ -153,7 +153,7 @@ static enum NTDB_ERROR check_entry(struct ntdb_context *ntdb, ...@@ -153,7 +153,7 @@ static enum NTDB_ERROR check_entry(struct ntdb_context *ntdb,
" %llu", (long long)off_and_hash); " %llu", (long long)off_and_hash);
} }
p = asearch(&off, used, num_used, off_cmp); p = asearch(&off, used, num_used, off_cmp, NULL);
if (!p) { if (!p) {
return ntdb_logerr(ntdb, NTDB_ERR_CORRUPT, NTDB_LOG_ERROR, return ntdb_logerr(ntdb, NTDB_ERR_CORRUPT, NTDB_LOG_ERROR,
"ntdb_check: Invalid offset" "ntdb_check: Invalid offset"
...@@ -430,7 +430,7 @@ static enum NTDB_ERROR check_free_table(struct ntdb_context *ntdb, ...@@ -430,7 +430,7 @@ static enum NTDB_ERROR check_free_table(struct ntdb_context *ntdb,
} }
/* FIXME: Check hash bits */ /* FIXME: Check hash bits */
p = asearch(&off, fr, num_free, off_cmp); p = asearch(&off, fr, num_free, off_cmp, NULL);
if (!p) { if (!p) {
return ntdb_logerr(ntdb, NTDB_ERR_CORRUPT, return ntdb_logerr(ntdb, NTDB_ERR_CORRUPT,
NTDB_LOG_ERROR, NTDB_LOG_ERROR,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment