From 57e7447c447249a33a13da853f8c1bfec546842a Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 20 Feb 2005 09:54:53 +0000 Subject: * Beef-up tests for str.count(). * Speed-up str.count() by using memchr() to fly between first char matches. --- Lib/test/string_tests.py | 28 ++++++++++++++++++++++++++++ Objects/stringobject.c | 9 +++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 0ce9618..f2173a7 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -114,6 +114,33 @@ class CommonTest(unittest.TestCase): self.checkraises(TypeError, 'hello', 'count') self.checkraises(TypeError, 'hello', 'count', 42) + # For a variety of combinations, + # verify that str.count() matches an equivalent function + # replacing all occurrences and then differencing the string lengths + charset = ['', 'a', 'b'] + digits = 7 + base = len(charset) + teststrings = set() + for i in xrange(base ** digits): + entry = [] + for j in xrange(digits): + i, m = divmod(i, base) + entry.append(charset[m]) + teststrings.add(''.join(entry)) + teststrings = list(teststrings) + for i in teststrings: + i = self.fixtype(i) + n = len(i) + for j in teststrings: + r1 = i.count(j) + if j: + r2, rem = divmod(n - len(i.replace(j, '')), len(j)) + else: + r2, rem = len(i)+1, 0 + if rem or r1 != r2: + self.assertEqual(rem, 0) + self.assertEqual(r1, r2) + def test_find(self): self.checkequal(0, 'abcdefghiabc', 'find', 'abc') self.checkequal(9, 'abcdefghiabc', 'find', 'abc', 1) @@ -135,6 +162,7 @@ class CommonTest(unittest.TestCase): i, m = divmod(i, base) entry.append(charset[m]) teststrings.add(''.join(entry)) + teststrings = list(teststrings) for i in teststrings: i = self.fixtype(i) for j in teststrings: diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 0cbf439..176e0d2b 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -2145,7 +2145,7 @@ interpreted as in slice notation."); static PyObject * string_count(PyStringObject *self, PyObject *args) { - const char *s = PyString_AS_STRING(self), *sub; + const char *s = PyString_AS_STRING(self), *sub, *t; int len = PyString_GET_SIZE(self), n; int i = 0, last = INT_MAX; int m, r; @@ -2186,11 +2186,16 @@ string_count(PyStringObject *self, PyObject *args) } else { i++; } + if (i >= m) + break; + t = memchr(s+i, sub[0], m-i); + if (t == NULL) + break; + i = t - s; } return PyInt_FromLong((long) r); } - PyDoc_STRVAR(swapcase__doc__, "S.swapcase() -> string\n\ \n\ -- cgit v0.12