summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorXinchen Hui <laruence@php.net>2015-01-12 17:24:37 +0800
committerXinchen Hui <laruence@php.net>2015-01-12 17:24:37 +0800
commit2f1ddff2a5f8d877537218c19137a4e8a022120a (patch)
treede4657593296c6f3618f16015d7e82a105920872 /Zend
parent31817447cc06093368f022086340ad3f6f616528 (diff)
downloadphp-git-2f1ddff2a5f8d877537218c19137a4e8a022120a.tar.gz
Faster strrpos implementation
Diffstat (limited to 'Zend')
-rw-r--r--Zend/zend_operators.c68
-rw-r--r--Zend/zend_operators.h45
2 files changed, 96 insertions, 17 deletions
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index 052623b97e..3bbe0ce924 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -2763,54 +2763,96 @@ process_double:
}
/* }}} */
-static zend_always_inline void zend_memstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len) /* {{{ */ {
+/*
+ * String matching - Sunday algorithm
+ * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
+ */
+static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
int i;
for (i = 0; i < 256; i++) {
td[i] = needle_len + 1;
}
- for (i = 0; i < needle_len; i++) {
- td[(unsigned char)needle[i]] = (int)needle_len - i;
+ if (reverse) {
+ for (i = needle_len - 1; i >= 0; i--) {
+ td[(unsigned char)needle[i]] = i + 1;
+ }
+ } else {
+ for (i = 0; i < needle_len; i++) {
+ td[(unsigned char)needle[i]] = (int)needle_len - i;
+ }
}
}
/* }}} */
-/*
- * String matching - Sunday algorithm
- * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
- */
ZEND_API const char* zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end) /* {{{ */
{
unsigned int td[256];
register size_t i;
- const unsigned register char *p;
+ register const char *p;
if (needle_len == 0 || (end - haystack) == 0) {
return NULL;
}
- zend_memstr_ex_pre(td, needle, needle_len);
+ zend_memnstr_ex_pre(td, needle, needle_len, 0);
- p = (const unsigned char *)haystack;
+ p = haystack;
end -= needle_len;
- while (p <= (unsigned char *)end) {
+ while (p <= end) {
for (i = 0; i < needle_len; i++) {
if (needle[i] != p[i]) {
break;
}
}
if (i == needle_len) {
- return (const char *)p;
+ return p;
}
- p += td[p[needle_len]];
+ p += td[(unsigned char)(p[needle_len])];
}
return NULL;
}
/* }}} */
+ZEND_API const char* zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end) /* {{{ */
+{
+ unsigned int td[256];
+ register size_t i;
+ register const char *p;
+
+ if (needle_len == 0 || (end - haystack) == 0) {
+ return NULL;
+ }
+
+ zend_memnstr_ex_pre(td, needle, needle_len, 1);
+
+ p = end;
+ p -= needle_len;
+
+ while (p >= haystack) {
+ for (i = 0; i < needle_len; i++) {
+ if (needle[i] != p[i]) {
+ break;
+ }
+ }
+
+ if (i == needle_len) {
+ return (const char *)p;
+ }
+
+ if (p == haystack) {
+ return NULL;
+ }
+
+ p -= td[(unsigned char)(p[-1])];
+ }
+
+ return NULL;
+}
+/* }}} */
/*
* Local variables:
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index ccbadc6f23..d57c4f59b1 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -88,6 +88,7 @@ ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, cons
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);
ZEND_API const char* zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end);
+ZEND_API const char* zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end);
END_EXTERN_C()
@@ -174,11 +175,12 @@ zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char *
size_t off_s;
if (needle_len == 1) {
- return (char *)memchr(p, *needle, (end-p));
+ return (const char *)memchr(p, *needle, (end-p));
}
off_p = end - haystack;
off_s = (off_p > 0) ? (size_t)off_p : 0;
+
if (needle_len > off_s) {
return NULL;
}
@@ -187,7 +189,7 @@ zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char *
end -= needle_len;
while (p <= end) {
- if ((p = (char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {
+ if ((p = (const char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {
if (!memcmp(needle, p, needle_len-1)) {
return p;
}
@@ -209,7 +211,6 @@ zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char *
static zend_always_inline const void *zend_memrchr(const void *s, int c, size_t n)
{
register const unsigned char *e;
-
if (n <= 0) {
return NULL;
}
@@ -219,10 +220,46 @@ static zend_always_inline const void *zend_memrchr(const void *s, int c, size_t
return (const void *)e;
}
}
-
return NULL;
}
+
+static zend_always_inline const char *
+zend_memnrstr(const char *haystack, const char *needle, size_t needle_len, char *end)
+{
+ const char *p = end;
+ const char ne = needle[needle_len-1];
+ ptrdiff_t off_p;
+ size_t off_s;
+
+ if (needle_len == 1) {
+ return (const char *)zend_memrchr(haystack, *needle, (p - haystack));
+ }
+
+ off_p = end - haystack;
+ off_s = (off_p > 0) ? (size_t)off_p : 0;
+
+ if (needle_len > off_s) {
+ return NULL;
+ }
+
+ if (EXPECTED(off_s < 1024 || needle_len < 3)) {
+ p -= needle_len;
+
+ do {
+ if ((p = (const char *)zend_memrchr(haystack, *needle, (p - haystack) + 1)) && ne == p[needle_len-1]) {
+ if (!memcmp(needle, p, needle_len - 1)) {
+ return p;
+ }
+ }
+ } while (p-- >= haystack);
+
+ return NULL;
+ } else {
+ return zend_memnrstr_ex(haystack, needle, needle_len, end);
+ }
+}
+
BEGIN_EXTERN_C()
ZEND_API int increment_function(zval *op1);
ZEND_API int decrement_function(zval *op2);