]> granicus.if.org Git - python/commitdiff
* Beef-up tests for str.count().
authorRaymond Hettinger <python@rcn.com>
Sun, 20 Feb 2005 09:54:53 +0000 (09:54 +0000)
committerRaymond Hettinger <python@rcn.com>
Sun, 20 Feb 2005 09:54:53 +0000 (09:54 +0000)
* Speed-up str.count() by using memchr() to fly between first char matches.

Lib/test/string_tests.py
Objects/stringobject.c

index 0ce96189af16e4031e74d4d13959a734e3951346..f2173a7b29caa972890133fd930dc33066a2247b 100644 (file)
@@ -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:
index 0cbf4390fc61a208c5318a8bd13ff91b60de7b71..176e0d2b611872c1ccc00e39ba1f7c497726a56d 100644 (file)
@@ -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\