diff options
Diffstat (limited to 'string/strcspn.c')
-rw-r--r-- | string/strcspn.c | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/string/strcspn.c b/string/strcspn.c index 8888919639..c535dd1c3d 100644 --- a/string/strcspn.c +++ b/string/strcspn.c @@ -16,6 +16,7 @@ <http://www.gnu.org/licenses/>. */ #include <string.h> +#include <stdint.h> #undef strcspn @@ -26,16 +27,45 @@ /* Return the length of the maximum initial segment of S which contains no characters from REJECT. */ size_t -STRCSPN (const char *s, const char *reject) +STRCSPN (const char *str, const char *reject) { - size_t count = 0; + if (__glibc_unlikely (reject[0] == '\0') || + __glibc_unlikely (reject[1] == '\0')) + return __strchrnul (str, reject [0]) - str; - while (*s != '\0') - if (strchr (reject, *s++) == NULL) - ++count; - else - return count; + /* Use multiple small memsets to enable inlining on most targets. */ + unsigned char table[256]; + unsigned char *p = memset (table, 0, 64); + memset (p + 64, 0, 64); + memset (p + 128, 0, 64); + memset (p + 192, 0, 64); - return count; + unsigned char *s = (unsigned char*) reject; + unsigned char tmp; + do + p[tmp = *s++] = 1; + while (tmp); + + s = (unsigned char*) str; + if (p[s[0]]) return 0; + if (p[s[1]]) return 1; + if (p[s[2]]) return 2; + if (p[s[3]]) return 3; + + s = (unsigned char *) ((uintptr_t)(s) & ~3); + + unsigned int c0, c1, c2, c3; + do + { + s += 4; + c0 = p[s[0]]; + c1 = p[s[1]]; + c2 = p[s[2]]; + c3 = p[s[3]]; + } + while ((c0 | c1 | c2 | c3) == 0); + + size_t count = s - (unsigned char *) str; + return (c0 | c1) != 0 ? count - c0 + 1 : count - c2 + 3; } libc_hidden_builtin_def (strcspn) |