From 68dbd05039f8b256f586ed9a589645fa3a1b7f5f Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 27 Sep 2012 17:19:09 -0400 Subject: [PATCH] optimize strchrnul/strcspn not to scan string twice on no-match 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 | 23 +++-------------------- src/string/strchrnul.c | 26 +++++++++++++++++++++++--- src/string/strcspn.c | 5 +++-- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/string/strchr.c b/src/string/strchr.c index d3563f18..bfae8f9f 100644 --- a/src/string/strchr.c +++ b/src/string/strchr.c @@ -1,26 +1,9 @@ #include -#include -#include -#include -#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; } diff --git a/src/string/strchrnul.c b/src/string/strchrnul.c index 5e0c1a1a..ceae4d45 100644 --- a/src/string/strchrnul.c +++ b/src/string/strchrnul.c @@ -1,7 +1,27 @@ #include +#include +#include +#include +#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); diff --git a/src/string/strcspn.c b/src/string/strcspn.c index c843ff97..cfdba114 100644 --- a/src/string/strcspn.c +++ b/src/string/strcspn.c @@ -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++); -- 2.20.1