optimize strchrnul/strcspn not to scan string twice on no-match
authorRich Felker <dalias@aerifal.cx>
Thu, 27 Sep 2012 21:19:09 +0000 (17:19 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 27 Sep 2012 21:19:09 +0000 (17:19 -0400)
when strchr fails, and important piece of information already
computed, the string length, is thrown away. have strchrnul (with
namespace protection) be the underlying function so this information
can be kept, and let strchr be a wrapper for it. this also allows
strcspn to be considerably faster in the case where the match set has
a single element that's not matched.

src/string/strchr.c
src/string/strchrnul.c
src/string/strcspn.c

index d3563f18c932d139b7b78f5e37a473518671a5a0..bfae8f9f846a01c14d288d34e8659f265a9daf2e 100644 (file)
@@ -1,26 +1,9 @@
 #include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <limits.h>
 
-#define ALIGN (sizeof(size_t)-1)
-#define ONES ((size_t)-1/UCHAR_MAX)
-#define HIGHS (ONES * (UCHAR_MAX/2+1))
-#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+char *__strchrnul(const char *, int);
 
 char *strchr(const char *s, int c)
 {
-       size_t *w, k;
-
-       c = (unsigned char)c;
-       if (!c) return (char *)s + strlen(s);
-
-       for (; ((uintptr_t)s & ALIGN); s++)
-               if (*(unsigned char *)s == c) return (char *)s;
-               else if (!*s) return 0;
-       k = ONES * c;
-       for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
-       for (s = (void *)w; *s; s++)
-               if (*(unsigned char *)s == c) return (char *)s;
-       return 0;
+       char *r = __strchrnul(s, c);
+       return *(unsigned char *)r == (unsigned char)c ? r : 0;
 }
index 5e0c1a1a4487667f85525a61a59270d44de32ff7..ceae4d45f22000fd3ee4e5f5ce86d67a1bcf7466 100644 (file)
@@ -1,7 +1,27 @@
 #include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include "libc.h"
 
-char *strchrnul(const char *s, int c)
+#define ALIGN (sizeof(size_t))
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+char *__strchrnul(const char *s, int c)
 {
-       char *p = strchr(s, c);
-       return p ? p : (char *)s + strlen(s);
+       size_t *w, k;
+
+       c = (unsigned char)c;
+       if (!c) return (char *)s + strlen(s);
+
+       for (; (uintptr_t)s % ALIGN; s++)
+               if (!*s || *(unsigned char *)s == c) return (char *)s;
+       k = ONES * c;
+       for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
+       for (s = (void *)w; *s && *(unsigned char *)s != c; s++);
+       return (char *)s;
 }
+
+weak_alias(__strchrnul, strchrnul);
index c843ff97476aedb4821fc41091689bfc8652fea2..cfdba114ca632ee86f433f7d00b744fb1fb6de19 100644 (file)
@@ -3,13 +3,14 @@
 #define BITOP(a,b,op) \
  ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
 
+char *__strchrnul(const char *, int);
+
 size_t strcspn(const char *s, const char *c)
 {
        const char *a = s;
        size_t byteset[32/sizeof(size_t)];
 
-       if (!c[0]) return strlen(s);
-       if (!c[1]) return (s=strchr(s, *c)) ? s-a : strlen(a);
+       if (!c[0] || !c[1]) return __strchrnul(s, *c)-a;
 
        memset(byteset, 0, sizeof byteset);
        for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++);