Skip to content

Commit 3181744

Browse files
committed
Faster zend_memnstr for long text
1 parent d805fa0 commit 3181744

File tree

3 files changed

+71
-13
lines changed

3 files changed

+71
-13
lines changed

UPGRADING

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ PHP X.Y UPGRADE NOTES
5454
. zend_function.common.num_args don't include the variadic argument anymore.
5555
. ob_start() no longer issues an E_ERROR, but instead an E_RECOVERABLE_ERROR in case an
5656
output buffer is created in an output buffer handler.
57+
. Add zend_memnstr_ex, which is based on string matching sunday algo.
5758

5859
- DBA
5960
. dba_delete() now returns false if the key was not found for the inifile

Zend/zend_operators.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2620,11 +2620,12 @@ ZEND_API zend_string *zend_long_to_str(zend_long num) /* {{{ */
26202620
}
26212621
/* }}} */
26222622

2623-
ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) {
2623+
ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */ {
26242624
return is_numeric_string_ex(str->val, str->len, lval, dval, -1, NULL);
26252625
}
2626+
/* }}} */
26262627

2627-
ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info)
2628+
ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) /* {{{ */
26282629
{
26292630
const char *ptr;
26302631
int base = 10, digits = 0, dp_or_e = 0;
@@ -2760,6 +2761,56 @@ ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_l
27602761
return IS_DOUBLE;
27612762
}
27622763
}
2764+
/* }}} */
2765+
2766+
static zend_always_inline void zend_memstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len) /* {{{ */ {
2767+
int i;
2768+
2769+
for (i = 0; i < 256; i++) {
2770+
td[i] = needle_len + 1;
2771+
}
2772+
2773+
for (i = 0; i < needle_len; i++) {
2774+
td[(unsigned char)needle[i]] = (int)needle_len - i;
2775+
}
2776+
}
2777+
/* }}} */
2778+
2779+
/*
2780+
* String matching - Sunday algorithm
2781+
* http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
2782+
*/
2783+
ZEND_API const char* zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end) /* {{{ */
2784+
{
2785+
unsigned int td[256];
2786+
register size_t i;
2787+
const unsigned register char *p;
2788+
2789+
if (needle_len == 0 || (end - haystack) == 0) {
2790+
return NULL;
2791+
}
2792+
2793+
zend_memstr_ex_pre(td, needle, needle_len);
2794+
2795+
p = (const unsigned char *)haystack;
2796+
end -= needle_len;
2797+
2798+
while (p <= (unsigned char *)end) {
2799+
for (i = 0; i < needle_len; i++) {
2800+
if (needle[i] != p[i]) {
2801+
break;
2802+
}
2803+
}
2804+
if (i == needle_len) {
2805+
return (const char *)p;
2806+
}
2807+
p += td[p[needle_len]];
2808+
}
2809+
2810+
return NULL;
2811+
}
2812+
/* }}} */
2813+
27632814

27642815
/*
27652816
* Local variables:

Zend/zend_operators.h

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, cons
8787
*/
8888
ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info);
8989

90+
ZEND_API const char* zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end);
91+
9092
END_EXTERN_C()
9193

9294
#if SIZEOF_ZEND_LONG == 4
@@ -181,23 +183,27 @@ zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char *
181183
return NULL;
182184
}
183185

184-
end -= needle_len;
186+
if (EXPECTED(off_s < 1024 || needle_len < 3)) {
187+
end -= needle_len;
185188

186-
while (p <= end) {
187-
if ((p = (char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {
188-
if (!memcmp(needle, p, needle_len-1)) {
189-
return p;
189+
while (p <= end) {
190+
if ((p = (char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {
191+
if (!memcmp(needle, p, needle_len-1)) {
192+
return p;
193+
}
194+
}
195+
196+
if (p == NULL) {
197+
return NULL;
190198
}
191-
}
192199

193-
if (p == NULL) {
194-
return NULL;
200+
p++;
195201
}
196202

197-
p++;
203+
return NULL;
204+
} else {
205+
return zend_memnstr_ex(haystack, needle, needle_len, end);
198206
}
199-
200-
return NULL;
201207
}
202208

203209
static zend_always_inline const void *zend_memrchr(const void *s, int c, size_t n)

0 commit comments

Comments
 (0)