From 70f21a8ebdbfe375155a71e1c29f3e548b3e255f Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Fri, 7 Aug 2026 15:01:32 -0500 Subject: T9182: simplify lexical_numeric_compare and catch corner case With bugs resolved, behavior remains as before, distinguishing numerical substrings containing leading 0's: this is to allow distinction in the case of arbitrary node name practices, such as "name1" and "name01". Equality of integer values is a matter for parsing/validation, not the comparator. --- src/lexical_numeric_compare.c | 92 +++++++++++++------------------------------ 1 file changed, 28 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/lexical_numeric_compare.c b/src/lexical_numeric_compare.c index 3905f3f..41910ed 100644 --- a/src/lexical_numeric_compare.c +++ b/src/lexical_numeric_compare.c @@ -1,79 +1,43 @@ /* * lexicographical-numeric compare */ -#include + +#include #include +#include #include -#include + +static int normalize(int v) { + return v == 0 ? 0 : (v / abs(v)); +} CAMLprim value caml_lex_numeric_compare(value str1, value str2) { - const char* inconsistent = "internal indexing error"; - mlsize_t len, len1, len2; - int pos, pos1, pos2; const char * s1, * s2; - const char * p1, * p2; - int n1, n2; - int res; - if (str1 == str2) return Val_int(0); - len1 = caml_string_length(str1); - len2 = caml_string_length(str2); - len = len1 <= len2 ? len1 : len2; s1 = String_val(str1); s2 = String_val(str2); - p1 = s1; - p2 = s2; - pos = 0; - do { - while ((pos < len) && (!isdigit(*s1) || !isdigit(*s2))) { - s1++; - s2++; - pos++; - } - if (pos > 0) { - res = memcmp(p1, p2, pos); - if (res < 0) return Val_int(-1); - if (res > 0) return Val_int(1); - if (pos == len) { - if (len1 < len2) return Val_int(-1); - if (len2 < len1) return Val_int(1); - return Val_int(0); - } - } - p1 = s1; - p2 = s2; - len = len - pos; - len1 = len1 - pos; - len2 = len2 - pos; - pos1 = pos2 = 0; - n1 = n2 = 0; - while ((pos1 < len1) && isdigit(*s1)) { - n1 = n1 * 10 + *s1 - '0'; - s1++; - pos1++; - } - while ((pos2 < len2) && isdigit(*s2)) { - n2 = n2 * 10 + *s2 - '0'; - s2++; - pos2++; - } - if (n1 < n2) return Val_int(-1); - if (n2 < n1) return Val_int(1); - if ((pos1 == len1) || (pos2 == len2)) { - if (len1 < len2) return Val_int(-1); - if (len2 < len1) return Val_int(1); - return Val_int(0); + while (*s1 && *s2) { + if (isdigit((unsigned char)*s1) && isdigit((unsigned char)*s2)) { + const char *ps1 = s1, *ps2 = s2; + + while (isdigit((unsigned char)*s1)) s1++; + while (isdigit((unsigned char)*s2)) s2++; + size_t ls1 = s1 - ps1, ls2 = s2 - ps2; + if (ls1 != ls2) return ls1 < ls2 ? Val_int(-1) : Val_int(1); + + int c = memcmp(ps1, ps2, ls1); + if (c) return Val_int(normalize(c)); + + } else { + if (*s1 != *s2) { + int res = (int)((unsigned char)*s1 - (unsigned char)*s2); + return Val_int(normalize(res)); + } + s1++; s2++; } - // if a sequence of 0's were encountered, it is possible that - // pos1 != pos2; adjust - pos = pos1 > pos2 ? pos2 : pos1; - p1 = s1; - p2 = s2; - len = len - pos; - len1 = len1 - pos; - len2 = len2 - pos; - pos = 0; - } while (*s1 && *s2); + } + int res = (int)((unsigned char)*s1 - (unsigned char)*s2); + return Val_int(normalize(res)); } -- cgit v1.2.3