quakeforge/libs/util/bsearch.c
Bill Currie 76ac446156 [util] Fix an out-by-one in QF_bsearch_r
And rename _bsearch to QF_bsearch_r since that's far less confusing.
Also, update the test to make it possible for valgrind to detect the
out-by-one. The problem was found when trying to remove components from
an entity when using subpools.
2023-03-05 18:31:30 +09:00

97 lines
1.8 KiB
C

#include <limits.h>
#include <string.h>
#include "QF/fbsearch.h"
#include "bsearch.h"
void *fbsearch (const void *key, const void *_base, size_t nmemb, size_t size,
__compar_fn_t cmp)
{
// fuzzy bsearh
const char *base = (const char *) _base;
unsigned left = 0;
unsigned right = nmemb - 1;
unsigned mid;
const void *p = 0;
if (!nmemb) {
return 0;
}
while (left != right) {
mid = (left + right + 1) / 2;
p = base + mid * size;
if (cmp (key, p) < 0) {
right = mid - 1;
} else {
left = mid;
}
}
p = base + left * size;
if (cmp (key, p) >= 0) {
return (void *) p;
}
return 0;
}
void *fbsearch_r (const void *key, const void *_base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg)
{
// fuzzy bsearh
const char *base = (const char *) _base;
unsigned left = 0;
unsigned right = nmemb - 1;
unsigned mid;
const void *p = 0;
if (!nmemb) {
return 0;
}
while (left != right) {
mid = (left + right + 1) / 2;
p = base + mid * size;
if (cmp (key, p, arg) < 0) {
right = mid - 1;
} else {
left = mid;
}
}
p = base + left * size;
if (cmp (key, p, arg) >= 0) {
return (void *) p;
}
return 0;
}
void *
QF_bsearch_r(const void *key, const void *_base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg)
{
const char *base = (const char *) _base;
unsigned left = 0;
unsigned right = nmemb - 1;
unsigned mid;
const void *p = 0;
int c;
if (!nmemb) {
return 0;
}
while (left != right) {
mid = (left + right + 1) / 2;
p = base + mid * size;
c = cmp (key, p, arg);
if (c == 0) {
return (void *) p;
}
if (c < 0) {
right = mid - 1;
} else {
left = mid;
}
}
p = base + left * size;
if (cmp (key, p, arg) == 0) {
return (void *) p;
}
return 0;
}