mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-07 15:37:46 +00:00
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.
This commit is contained in:
parent
a49340c3e5
commit
851ad65081
60
src/tsort.c
60
src/tsort.c
@ -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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
} 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
|||||||
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 {
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
}\
|
}\
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
}
|
||||||
|
33
src/util.c
33
src/util.c
@ -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(
|
|||||||
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
|
||||||
*
|
*
|
||||||
|
20
src/util.h
20
src/util.h
@ -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(
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user