UINT extension tweak suggestion
(1) By Mark Scandariato (scandariato) on 2021-11-30 16:20:12 [source]
I guess I missed all the fun last year, having just noticed this extension.
I see that it may scan its inputs twice. This similar function only scans its inputs once, using the fact that big-endian numbers of the same length can be sorted by their leftmost different digit. (I've been using it for a "version" collating sequence, to order semantic versions.)
#define are_digits(a, b) (isdigit(a) && isdigit(b))
static int versioncmp (void *state, int len1, const void *v1, int len2, const void *v2)
{
(void)state;
const unsigned char *a = v1;
const unsigned char *b = v2;
int i = 0;
int j = 0;
int rc = 0;
while (rc==0 && i<len1 && j<len2) {
if (!are_digits(a[i], b[j])) {
rc = a[i] - b[j];
} else {
// skip leading zeros
while (i<len1 && a[i] == '0') i++;
while (j<len2 && b[j] == '0') j++;
// compare pairs of digits until we run out of pairs
for (; i<len1 && j<len2 && are_digits(a[i], b[j]); i++, j++) {
// latch the leftmost difference
if (!rc) rc = a[i] - b[j];
}
// does one string have more digits?
if (i<len1 && isdigit(a[i])) return +1;
if (j<len2 && isdigit(b[j])) return -1;
continue;
}
i++;
j++;
}
return rc ? rc : (len1 - i) - (len2 - j);
}