Skip to content

Optimize strspn() #12431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 30 additions & 9 deletions ext/standard/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -1599,17 +1599,38 @@ PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
/* {{{ php_strspn */
PHPAPI size_t php_strspn(const char *s1, const char *s2, const char *s1_end, const char *s2_end)
{
const char *p = s1, *spanp;
char c = *p;

cont:
for (spanp = s2; p != s1_end && spanp != s2_end;) {
if (*spanp++ == c) {
c = *(++p);
goto cont;
/* Fast path for short strings.
* The table lookup cannot be faster in this case because we not only have to compare, but
* also build the table. We only compare in this case.
* Empirically tested that the table lookup approach is only beneficial for s2 longer than 1 character. */
if (s2_end - s2 == 1) {
const char *ptr = s1;
while (ptr < s1_end && *ptr == *s2) {
ptr++;
}
return ptr - s1;
}

/* Every character in s2 will set a boolean in this lookup table.
* We'll use the lookup table as a fast lookup for the characters in s2 while looping over s1. */
bool table[256];
/* Use multiple small memsets to inline the memset with intrinsics, trick learned from glibc. */
memset(table, 0, 64);
memset(table + 64, 0, 64);
memset(table + 128, 0, 64);
memset(table + 192, 0, 64);

while (s2 < s2_end) {
table[(unsigned char) *s2] = true;
s2++;
}

const char *ptr = s1;
while (ptr < s1_end && table[(unsigned char) *ptr]) {
ptr++;
}
return (p - s1);

return ptr - s1;
}
/* }}} */

Expand Down