* [PATCH] strverscmp fix
@ 2015-06-21 4:30 Rich Felker
2015-06-23 1:07 ` Rich Felker
0 siblings, 1 reply; 2+ messages in thread
From: Rich Felker @ 2015-06-21 4:30 UTC (permalink / raw)
To: musl
[-- Attachment #1: Type: text/plain, Size: 472 bytes --]
Fixing strverscmp behavior to match glibc has been an open item for a
while. There's a patch (or rather replacement) from Sergey Dmitrouk
that's been pending review serious for a few months now, and while it
reportedly works, I found myself writing my own version in the process
of reviewing and trying to understand all the cases. The attached is
what I ended up with, and I believe it's correct and about 20%
smaller. I couldn't find any further ways to simplify.
Rich
[-- Attachment #2: strverscmp.diff --]
[-- Type: text/plain, Size: 2018 bytes --]
diff --git a/src/string/strverscmp.c b/src/string/strverscmp.c
index 6f37cc6..9c7fa33 100644
--- a/src/string/strverscmp.c
+++ b/src/string/strverscmp.c
@@ -2,6 +2,55 @@
#include <ctype.h>
#include <string.h>
+#if 1
+int strverscmp(const char *l0, const char *r0)
+{
+ const unsigned char *l = (const void *)l0;
+ const unsigned char *r = (const void *)r0;
+ size_t i, dp, j;
+ int z = 1;
+
+ /* Find maximual matching prefix and track its maximal digit
+ * suffix and whether those digits are all zeros. */
+ for (dp=i=0; l[i]==r[i]; i++) {
+ int c = l[i];
+ if (!c) return 0;
+ if (!isdigit(c)) dp=i+1, z=1;
+ else if (c!='0') z=0;
+ }
+
+ /* This catches all cases where the mismatch is non-numeric --
+ * either a matching digit sequence has just been completed and
+ * is followed by non-digits in both strings, or at most one
+ * of the two strings has an initial digit in the first
+ * mismatched position and the other has a non-digit. */
+ if (!isdigit(l[i]) && !isdigit(r[i]) ||
+ i==dp && (!isdigit(l[i]) || !isdigit(r[i])))
+ return l[i] - r[i];
+
+ /* If this point is reached, the comparison is numeric. */
+
+ /* The only way one of the conditions can hold without the other
+ * is when dp==i, i.e. the mismatch is the start of a new
+ * digit sequence in both strings. */
+ if (l[dp]=='0' || r[dp]=='0') {
+ /* If the shared prefix is all zeros, 0<d<x; otherwise,
+ * x<0<d, where d is any nonzero digit, x any non-digit.
+ * Arrange for unsigned range check. */
+ unsigned adj = '0' + (z?0:10);
+ return l[i]-adj > r[i]-adj ? 1 : -1;
+ }
+
+ /* In the only remaining cases, neither number has leading zeros.
+ * The longer is greater, with first mismatch breaking ties. */
+
+ for (j=i; isdigit(l[j]); j++)
+ if (!isdigit(r[j])) return 1;
+ if (isdigit(r[j])) return -1;
+
+ return l[i] - r[i];
+}
+#else
int strverscmp(const char *l, const char *r)
{
int haszero=1;
@@ -39,3 +88,4 @@ int strverscmp(const char *l, const char *r)
return (*l - *r);
}
}
+#endif
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] strverscmp fix
2015-06-21 4:30 [PATCH] strverscmp fix Rich Felker
@ 2015-06-23 1:07 ` Rich Felker
0 siblings, 0 replies; 2+ messages in thread
From: Rich Felker @ 2015-06-23 1:07 UTC (permalink / raw)
To: musl
On Sun, Jun 21, 2015 at 12:30:18AM -0400, Rich Felker wrote:
> Fixing strverscmp behavior to match glibc has been an open item for a
> while. There's a patch (or rather replacement) from Sergey Dmitrouk
> that's been pending review serious for a few months now, and while it
> reportedly works, I found myself writing my own version in the process
> of reviewing and trying to understand all the cases. The attached is
> what I ended up with, and I believe it's correct and about 20%
> smaller. I couldn't find any further ways to simplify.
This was much more complex than it needed to be; I'm committing a new
version that barely affects the compiled code size now.
Rich
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2015-06-23 1:07 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-21 4:30 [PATCH] strverscmp fix Rich Felker
2015-06-23 1:07 ` Rich Felker
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/musl/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).