[Python-checkins] r46230 - python/trunk/Objects/stringobject.c
Neal Norwitz
nnorwitz at gmail.com
Fri May 26 08:19:43 CEST 2006
See my previous comments on this code in unicodeobject.c. In
particular, count needs to be a Py_ssize_t. If you've already fixed,
sorry, I'm trying to catch up on mail. :-(
n
--
On 5/25/06, fredrik.lundh <python-checkins at python.org> wrote:
> Author: fredrik.lundh
> Date: Thu May 25 19:55:31 2006
> New Revision: 46230
>
> Modified:
> python/trunk/Objects/stringobject.c
> Log:
> needforspeed: use "fastsearch" for count. this results in a 3x speedup
> for the related stringbench tests.
>
>
>
> Modified: python/trunk/Objects/stringobject.c
> ==============================================================================
> --- python/trunk/Objects/stringobject.c (original)
> +++ python/trunk/Objects/stringobject.c Thu May 25 19:55:31 2006
> @@ -5,6 +5,18 @@
>
> #include <ctype.h>
>
> +#undef USE_INLINE /* XXX - set via configure? */
> +
> +#if defined(_MSC_VER) /* this is taken from _sre.c */
> +#pragma warning(disable: 4710)
> +/* fastest possible local call under MSVC */
> +#define LOCAL(type) static __inline type __fastcall
> +#elif defined(USE_INLINE)
> +#define LOCAL(type) static inline type
> +#else
> +#define LOCAL(type) static type
> +#endif
> +
> #ifdef COUNT_ALLOCS
> int null_strings, one_strings;
> #endif
> @@ -763,6 +775,108 @@
> return 0;
> }
>
> +/* -------------------------------------------------------------------- */
> +/* Helpers */
> +
> +#define USE_FAST /* experimental fast search implementation */
> +
> +/* XXX - this code is copied from unicodeobject.c. we really should
> + refactor the core implementations (see _sre.c for how this can be
> + done), but that'll have to wait -- fredrik */
> +
> +/* fast search/count implementation, based on a mix between boyer-
> + moore and horspool, with a few more bells and whistles on the top.
> + for some more background, see: http://effbot.org/stringlib */
> +
> +/* note: fastsearch may access s[n], which isn't a problem when using
> + Python's ordinary string types, but may cause problems if you're
> + using this code in other contexts. also, the count mode returns -1
> + if there cannot possible be a match in the target string, and 0 if
> + it has actually checked for matches, but didn't find any. callers
> + beware! */
> +
> +#define FAST_COUNT 0
> +#define FAST_SEARCH 1
> +
> +LOCAL(Py_ssize_t)
> + fastsearch(const unsigned char* s, Py_ssize_t n, const unsigned char* p,
> + Py_ssize_t m, int mode)
> +{
> + long mask;
> + int skip, count = 0;
> + Py_ssize_t i, j, mlast, w;
> +
> + w = n - m;
> +
> + if (w < 0)
> + return -1;
> +
> + /* look for special cases */
> + if (m <= 1) {
> + if (m <= 0)
> + return -1;
> + /* use special case for 1-character strings */
> + if (mode == FAST_COUNT) {
> + for (i = 0; i < n; i++)
> + if (s[i] == p[0])
> + count++;
> + return count;
> + } else {
> + for (i = 0; i < n; i++)
> + if (s[i] == p[0])
> + return i;
> + }
> + return -1;
> + }
> +
> + mlast = m - 1;
> +
> + /* create compressed boyer-moore delta 1 table */
> + skip = mlast - 1;
> + /* process pattern[:-1] */
> + for (mask = i = 0; i < mlast; i++) {
> + mask |= (1 << (p[i] & 0x1F));
> + if (p[i] == p[mlast])
> + skip = mlast - i - 1;
> + }
> + /* process pattern[-1] outside the loop */
> + mask |= (1 << (p[mlast] & 0x1F));
> +
> + for (i = 0; i <= w; i++) {
> + /* note: using mlast in the skip path slows things down on x86 */
> + if (s[i+m-1] == p[m-1]) {
> + /* candidate match */
> + for (j = 0; j < mlast; j++)
> + if (s[i+j] != p[j])
> + break;
> + if (j == mlast) {
> + /* got a match! */
> + if (mode != FAST_COUNT)
> + return i;
> + count++;
> + i = i + mlast;
> + continue;
> + }
> + /* miss: check if next character is part of pattern */
> + if (!(mask & (1 << (s[i+m] & 0x1F))))
> + i = i + m;
> + else {
> + i = i + skip;
> + continue;
> + }
> + } else {
> + /* skip: check if next character is part of pattern */
> + if (!(mask & (1 << (s[i+m] & 0x1F))))
> + i = i + m;
> + }
> + }
> +
> + if (mode != FAST_COUNT)
> + return -1;
> + return count;
> +}
> +
> +/* -------------------------------------------------------------------- */
> /* Methods */
>
> static int
> @@ -2177,7 +2291,7 @@
> static PyObject *
> string_count(PyStringObject *self, PyObject *args)
> {
> - const char *s = PyString_AS_STRING(self), *sub, *t;
> + const char *s = PyString_AS_STRING(self), *sub;
> Py_ssize_t len = PyString_GET_SIZE(self), n;
> Py_ssize_t i = 0, last = PY_SSIZE_T_MAX;
> Py_ssize_t m, r;
> @@ -2210,8 +2324,14 @@
> if (n == 0)
> return PyInt_FromSsize_t(m-i);
>
> +#ifdef USE_FAST
> + r = fastsearch(s + i, last - i, sub, n, FAST_COUNT);
> + if (r < 0)
> + r = 0; /* no match */
> +#else
> r = 0;
> while (i < m) {
> + const char *t
> if (!memcmp(s+i, sub, n)) {
> r++;
> i += n;
> @@ -2225,6 +2345,7 @@
> break;
> i = t - s;
> }
> +#endif
> return PyInt_FromSsize_t(r);
> }
>
> _______________________________________________
> Python-checkins mailing list
> Python-checkins at python.org
> http://mail.python.org/mailman/listinfo/python-checkins
>
More information about the Python-checkins
mailing list