Commit 851ad650 by Russell Belfer

Add payload "_r" versions of bsearch and tsort

git__bsearch and git__tsort did not pass a payload through to the
comparison function.  This makes it impossible to implement sorted
lists where the sort order depends on external data (e.g. building
a secondary sort order for the entries in a tree).  This commit
adds git__bsearch_r and git__tsort_r versions that pass a third
parameter to the cmp function of a user payload.
parent a49340c3
...@@ -23,9 +23,8 @@ ...@@ -23,9 +23,8 @@
# define MIN(x,y) (((x) < (y) ? (x) : (y))) # define MIN(x,y) (((x) < (y) ? (x) : (y)))
#endif #endif
typedef int (*cmp_ptr_t)(const void *, const void *); static int binsearch(
void **dst, const void *x, size_t size, git__tsort_r_cmp cmp, void *payload)
static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
{ {
int l, c, r; int l, c, r;
void *lx, *cx; void *lx, *cx;
...@@ -38,12 +37,12 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp) ...@@ -38,12 +37,12 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
lx = dst[l]; lx = dst[l];
/* check for beginning conditions */ /* check for beginning conditions */
if (cmp(x, lx) < 0) if (cmp(x, lx, payload) < 0)
return 0; return 0;
else if (cmp(x, lx) == 0) { else if (cmp(x, lx, payload) == 0) {
int i = 1; int i = 1;
while (cmp(x, dst[i]) == 0) while (cmp(x, dst[i], payload) == 0)
i++; i++;
return i; return i;
} }
...@@ -51,7 +50,7 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp) ...@@ -51,7 +50,7 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
/* guaranteed not to be >= rx */ /* guaranteed not to be >= rx */
cx = dst[c]; cx = dst[c];
while (1) { while (1) {
const int val = cmp(x, cx); const int val = cmp(x, cx, payload);
if (val < 0) { if (val < 0) {
if (c - l <= 1) return c; if (c - l <= 1) return c;
r = c; r = c;
...@@ -62,7 +61,7 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp) ...@@ -62,7 +61,7 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
} else { } else {
do { do {
cx = dst[++c]; cx = dst[++c];
} while (cmp(x, cx) == 0); } while (cmp(x, cx, payload) == 0);
return c; return c;
} }
c = l + ((r - l) >> 1); c = l + ((r - l) >> 1);
...@@ -71,7 +70,8 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp) ...@@ -71,7 +70,8 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
} }
/* Binary insertion sort, but knowing that the first "start" entries are sorted. Used in timsort. */ /* Binary insertion sort, but knowing that the first "start" entries are sorted. Used in timsort. */
static void bisort(void **dst, size_t start, size_t size, cmp_ptr_t cmp) static void bisort(
void **dst, size_t start, size_t size, git__tsort_r_cmp cmp, void *payload)
{ {
size_t i; size_t i;
void *x; void *x;
...@@ -80,12 +80,12 @@ static void bisort(void **dst, size_t start, size_t size, cmp_ptr_t cmp) ...@@ -80,12 +80,12 @@ static void bisort(void **dst, size_t start, size_t size, cmp_ptr_t cmp)
for (i = start; i < size; i++) { for (i = start; i < size; i++) {
int j; int j;
/* If this entry is already correct, just move along */ /* If this entry is already correct, just move along */
if (cmp(dst[i - 1], dst[i]) <= 0) if (cmp(dst[i - 1], dst[i], payload) <= 0)
continue; continue;
/* Else we need to find the right place, shift everything over, and squeeze in */ /* Else we need to find the right place, shift everything over, and squeeze in */
x = dst[i]; x = dst[i];
location = binsearch(dst, x, i, cmp); location = binsearch(dst, x, i, cmp, payload);
for (j = (int)i - 1; j >= location; j--) { for (j = (int)i - 1; j >= location; j--) {
dst[j + 1] = dst[j]; dst[j + 1] = dst[j];
} }
...@@ -102,7 +102,8 @@ struct tsort_run { ...@@ -102,7 +102,8 @@ struct tsort_run {
struct tsort_store { struct tsort_store {
size_t alloc; size_t alloc;
cmp_ptr_t cmp; git__tsort_r_cmp cmp;
void *payload;
void **storage; void **storage;
}; };
...@@ -118,7 +119,8 @@ static void reverse_elements(void **dst, ssize_t start, ssize_t end) ...@@ -118,7 +119,8 @@ static void reverse_elements(void **dst, ssize_t start, ssize_t end)
} }
} }
static ssize_t count_run(void **dst, ssize_t start, ssize_t size, struct tsort_store *store) static ssize_t count_run(
void **dst, ssize_t start, ssize_t size, struct tsort_store *store)
{ {
ssize_t curr = start + 2; ssize_t curr = start + 2;
...@@ -126,7 +128,7 @@ static ssize_t count_run(void **dst, ssize_t start, ssize_t size, struct tsort_s ...@@ -126,7 +128,7 @@ static ssize_t count_run(void **dst, ssize_t start, ssize_t size, struct tsort_s
return 1; return 1;
if (start >= size - 2) { if (start >= size - 2) {
if (store->cmp(dst[size - 2], dst[size - 1]) > 0) { if (store->cmp(dst[size - 2], dst[size - 1], store->payload) > 0) {
void *tmp = dst[size - 1]; void *tmp = dst[size - 1];
dst[size - 1] = dst[size - 2]; dst[size - 1] = dst[size - 2];
dst[size - 2] = tmp; dst[size - 2] = tmp;
...@@ -135,13 +137,15 @@ static ssize_t count_run(void **dst, ssize_t start, ssize_t size, struct tsort_s ...@@ -135,13 +137,15 @@ static ssize_t count_run(void **dst, ssize_t start, ssize_t size, struct tsort_s
return 2; return 2;
} }
if (store->cmp(dst[start], dst[start + 1]) <= 0) { if (store->cmp(dst[start], dst[start + 1], store->payload) <= 0) {
while (curr < size - 1 && store->cmp(dst[curr - 1], dst[curr]) <= 0) while (curr < size - 1 &&
store->cmp(dst[curr - 1], dst[curr], store->payload) <= 0)
curr++; curr++;
return curr - start; return curr - start;
} else { } else {
while (curr < size - 1 && store->cmp(dst[curr - 1], dst[curr]) > 0) while (curr < size - 1 &&
store->cmp(dst[curr - 1], dst[curr], store->payload) > 0)
curr++; curr++;
/* reverse in-place */ /* reverse in-place */
...@@ -219,7 +223,7 @@ static void merge(void **dst, const struct tsort_run *stack, ssize_t stack_curr, ...@@ -219,7 +223,7 @@ static void merge(void **dst, const struct tsort_run *stack, ssize_t stack_curr,
for (k = curr; k < curr + A + B; k++) { for (k = curr; k < curr + A + B; k++) {
if ((i < A) && (j < curr + A + B)) { if ((i < A) && (j < curr + A + B)) {
if (store->cmp(storage[i], dst[j]) <= 0) if (store->cmp(storage[i], dst[j], store->payload) <= 0)
dst[k] = storage[i++]; dst[k] = storage[i++];
else else
dst[k] = dst[j++]; dst[k] = dst[j++];
...@@ -235,7 +239,7 @@ static void merge(void **dst, const struct tsort_run *stack, ssize_t stack_curr, ...@@ -235,7 +239,7 @@ static void merge(void **dst, const struct tsort_run *stack, ssize_t stack_curr,
for (k = curr + A + B - 1; k >= curr; k--) { for (k = curr + A + B - 1; k >= curr; k--) {
if ((i >= 0) && (j >= curr)) { if ((i >= 0) && (j >= curr)) {
if (store->cmp(dst[j], storage[i]) > 0) if (store->cmp(dst[j], storage[i], store->payload) > 0)
dst[k] = dst[j--]; dst[k] = dst[j--];
else else
dst[k] = storage[i--]; dst[k] = storage[i--];
...@@ -307,7 +311,7 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr, ...@@ -307,7 +311,7 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr,
if (run < minrun) run = minrun;\ if (run < minrun) run = minrun;\
if (run > (ssize_t)size - curr) run = size - curr;\ if (run > (ssize_t)size - curr) run = size - curr;\
if (run > len) {\ if (run > len) {\
bisort(&dst[curr], len, run, cmp);\ bisort(&dst[curr], len, run, cmp, payload);\
len = run;\ len = run;\
}\ }\
run_stack[stack_curr].start = curr;\ run_stack[stack_curr].start = curr;\
...@@ -329,7 +333,8 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr, ...@@ -329,7 +333,8 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr,
}\ }\
while (0) while (0)
void git__tsort(void **dst, size_t size, cmp_ptr_t cmp) void git__tsort_r(
void **dst, size_t size, git__tsort_r_cmp cmp, void *payload)
{ {
struct tsort_store _store, *store = &_store; struct tsort_store _store, *store = &_store;
struct tsort_run run_stack[128]; struct tsort_run run_stack[128];
...@@ -340,7 +345,7 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp) ...@@ -340,7 +345,7 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
ssize_t minrun; ssize_t minrun;
if (size < 64) { if (size < 64) {
bisort(dst, 1, size, cmp); bisort(dst, 1, size, cmp, payload);
return; return;
} }
...@@ -351,6 +356,7 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp) ...@@ -351,6 +356,7 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
store->alloc = 0; store->alloc = 0;
store->storage = NULL; store->storage = NULL;
store->cmp = cmp; store->cmp = cmp;
store->payload = payload;
PUSH_NEXT(); PUSH_NEXT();
PUSH_NEXT(); PUSH_NEXT();
...@@ -365,3 +371,13 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp) ...@@ -365,3 +371,13 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
PUSH_NEXT(); PUSH_NEXT();
} }
} }
static int tsort_r_cmp(const void *a, const void *b, void *payload)
{
return ((git__tsort_cmp)payload)(a, b);
}
void git__tsort(void **dst, size_t size, git__tsort_cmp cmp)
{
git__tsort_r(dst, size, tsort_r_cmp, cmp);
}
...@@ -462,7 +462,7 @@ uint32_t git__hash(const void *key, int len, uint32_t seed) ...@@ -462,7 +462,7 @@ uint32_t git__hash(const void *key, int len, uint32_t seed)
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
int git__bsearch( int git__bsearch(
void **array, void **array,
size_t array_len, size_t array_len,
...@@ -493,6 +493,37 @@ int git__bsearch( ...@@ -493,6 +493,37 @@ int git__bsearch(
return (cmp == 0) ? 0 : -1; return (cmp == 0) ? 0 : -1;
} }
int git__bsearch_r(
void **array,
size_t array_len,
const void *key,
int (*compare_r)(const void *, const void *, void *),
void *payload,
size_t *position)
{
unsigned int lim;
int cmp = -1;
void **part, **base = array;
for (lim = (unsigned int)array_len; lim != 0; lim >>= 1) {
part = base + (lim >> 1);
cmp = (*compare_r)(key, *part, payload);
if (cmp == 0) {
base = part;
break;
}
if (cmp > 0) { /* key > p; take right partition */
base = part + 1;
lim--;
} /* else take left partition */
}
if (position)
*position = (base - array);
return (cmp == 0) ? 0 : -1;
}
/** /**
* A strcmp wrapper * A strcmp wrapper
* *
......
...@@ -119,7 +119,15 @@ GIT_INLINE(const char *) git__next_line(const char *s) ...@@ -119,7 +119,15 @@ GIT_INLINE(const char *) git__next_line(const char *s)
return s; return s;
} }
extern void git__tsort(void **dst, size_t size, int (*cmp)(const void *, const void *)); typedef int (*git__tsort_cmp)(const void *a, const void *b);
extern void git__tsort(void **dst, size_t size, git__tsort_cmp cmp);
typedef int (*git__tsort_r_cmp)(const void *a, const void *b, void *payload);
extern void git__tsort_r(
void **dst, size_t size, git__tsort_r_cmp cmp, void *payload);
/** /**
* @param position If non-NULL, this will be set to the position where the * @param position If non-NULL, this will be set to the position where the
...@@ -130,7 +138,15 @@ extern int git__bsearch( ...@@ -130,7 +138,15 @@ extern int git__bsearch(
void **array, void **array,
size_t array_len, size_t array_len,
const void *key, const void *key,
int (*compare)(const void *, const void *), int (*compare)(const void *key, const void *element),
size_t *position);
extern int git__bsearch_r(
void **array,
size_t array_len,
const void *key,
int (*compare_r)(const void *key, const void *element, void *payload),
void *payload,
size_t *position); size_t *position);
extern int git__strcmp_cb(const void *a, const void *b); extern int git__strcmp_cb(const void *a, const void *b);
......
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