| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 2952148 commit da2ecaf
10 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -767,6 +767,8 @@ def replace(self, old, new, maxsplit=-1): | |||
| 767 | 767 | new = new.data | |
| 768 | 768 | return self.__class__(self.data.replace(old, new, maxsplit)) | |
| 769 | 769 | def rfind(self, sub, start=0, end=_sys.maxsize): | |
| 770 | + if isinstance(sub, UserString): | ||
| 771 | + sub = sub.data | ||
| 770 | 772 | return self.data.rfind(sub, start, end) | |
| 771 | 773 | def rindex(self, sub, start=0, end=_sys.maxsize): | |
| 772 | 774 | return self.data.rindex(sub, start, end) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -216,6 +216,30 @@ def test_rfind(self): | |||
| 216 | 216 | self.checkraises(TypeError, 'hello', 'rfind') | |
| 217 | 217 | self.checkraises(TypeError, 'hello', 'rfind', 42) | |
| 218 | 218 | ||
| 219 | + # For a variety of combinations, | ||
| 220 | + # verify that str.rfind() matches __contains__ | ||
| 221 | + # and that the found substring is really at that location | ||
| 222 | + charset = ['', 'a', 'b', 'c'] | ||
| 223 | + digits = 5 | ||
| 224 | + base = len(charset) | ||
| 225 | + teststrings = set() | ||
| 226 | + for i in range(base ** digits): | ||
| 227 | + entry = [] | ||
| 228 | + for j in range(digits): | ||
| 229 | + i, m = divmod(i, base) | ||
| 230 | + entry.append(charset[m]) | ||
| 231 | + teststrings.add(''.join(entry)) | ||
| 232 | + teststrings = [self.fixtype(ts) for ts in teststrings] | ||
| 233 | + for i in teststrings: | ||
| 234 | + for j in teststrings: | ||
| 235 | + loc = i.rfind(j) | ||
| 236 | + r1 = (loc != -1) | ||
| 237 | + r2 = j in i | ||
| 238 | + if r1 != r2: | ||
| 239 | + self.assertEqual(r1, r2) | ||
| 240 | + if loc != -1: | ||
| 241 | + self.assertEqual(i[loc:loc+len(j)], j) | ||
| 242 | + | ||
| 219 | 243 | def test_index(self): | |
| 220 | 244 | self.checkequal(0, 'abcdefghiabc', 'index', '') | |
| 221 | 245 | self.checkequal(3, 'abcdefghiabc', 'index', 'def') | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -12,6 +12,9 @@ What's New in Python 3.2 Alpha 1? | |||
| 12 | 12 | Core and Builtins | |
| 13 | 13 | ----------------- | |
| 14 | 14 | ||
| 15 | + - Issue #7462: Implement the stringlib fast search algorithm for the `rfind`, | ||
| 16 | + `rindex`, `rsplit` and `rpartition` methods. Patch by Florent Xicluna. | ||
| 17 | + | ||
| 15 | 18 | - Issue #7604: Deleting an unset slotted attribute did not raise an | |
| 16 | 19 | AttributeError. | |
| 17 | 20 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1035,7 +1035,6 @@ bytearray_dealloc(PyByteArrayObject *self) | |||
| 1035 | 1035 | /* Methods */ | |
| 1036 | 1036 | ||
| 1037 | 1037 | #define STRINGLIB_CHAR char | |
| 1038 | - #define STRINGLIB_CMP memcmp | ||
| 1039 | 1038 | #define STRINGLIB_LEN PyByteArray_GET_SIZE | |
| 1040 | 1039 | #define STRINGLIB_STR PyByteArray_AS_STRING | |
| 1041 | 1040 | #define STRINGLIB_NEW PyByteArray_FromStringAndSize | |
@@ -2214,14 +2213,11 @@ If maxsplit is given, at most maxsplit splits are done."); | |||
| 2214 | 2213 | static PyObject * | |
| 2215 | 2214 | bytearray_split(PyByteArrayObject *self, PyObject *args) | |
| 2216 | 2215 | { | |
| 2217 | - Py_ssize_t len = PyByteArray_GET_SIZE(self), n, i, j; | ||
| 2216 | + Py_ssize_t len = PyByteArray_GET_SIZE(self), n, i, j, pos; | ||
| 2218 | 2217 | Py_ssize_t maxsplit = -1, count = 0; | |
| 2219 | 2218 | const char *s = PyByteArray_AS_STRING(self), *sub; | |
| 2220 | 2219 | PyObject *list, *str, *subobj = Py_None; | |
| 2221 | 2220 | Py_buffer vsub; | |
| 2222 | - #ifdef USE_FAST | ||
| 2223 | - Py_ssize_t pos; | ||
| 2224 | - #endif | ||
| 2225 | 2221 | ||
| 2226 | 2222 | if (!PyArg_ParseTuple(args, "|On:split", &subobj, &maxsplit)) | |
| 2227 | 2223 | return NULL; | |
@@ -2253,7 +2249,6 @@ bytearray_split(PyByteArrayObject *self, PyObject *args) | |||
| 2253 | 2249 | return NULL; | |
| 2254 | 2250 | } | |
| 2255 | 2251 | ||
| 2256 | - #ifdef USE_FAST | ||
| 2257 | 2252 | i = j = 0; | |
| 2258 | 2253 | while (maxsplit-- > 0) { | |
| 2259 | 2254 | pos = fastsearch(s+i, len-i, sub, n, FAST_SEARCH); | |
@@ -2263,18 +2258,6 @@ bytearray_split(PyByteArrayObject *self, PyObject *args) | |||
| 2263 | 2258 | SPLIT_ADD(s, i, j); | |
| 2264 | 2259 | i = j + n; | |
| 2265 | 2260 | } | |
| 2266 | - #else | ||
| 2267 | - i = j = 0; | ||
| 2268 | - while ((j+n <= len) && (maxsplit-- > 0)) { | ||
| 2269 | - for (; j+n <= len; j++) { | ||
| 2270 | - if (Py_STRING_MATCH(s, j, sub, n)) { | ||
| 2271 | - SPLIT_ADD(s, i, j); | ||
| 2272 | - i = j = j + n; | ||
| 2273 | - break; | ||
| 2274 | - } | ||
| 2275 | - } | ||
| 2276 | - } | ||
| 2277 | - #endif | ||
| 2278 | 2261 | SPLIT_ADD(s, i, len); | |
| 2279 | 2262 | FIX_PREALLOC_SIZE(list); | |
| 2280 | 2263 | PyBuffer_Release(&vsub); | |
@@ -2452,7 +2435,7 @@ If maxsplit is given, at most maxsplit splits are done."); | |||
| 2452 | 2435 | static PyObject * | |
| 2453 | 2436 | bytearray_rsplit(PyByteArrayObject *self, PyObject *args) | |
| 2454 | 2437 | { | |
| 2455 | - Py_ssize_t len = PyByteArray_GET_SIZE(self), n, i, j; | ||
| 2438 | + Py_ssize_t len = PyByteArray_GET_SIZE(self), n, j, pos; | ||
| 2456 | 2439 | Py_ssize_t maxsplit = -1, count = 0; | |
| 2457 | 2440 | const char *s = PyByteArray_AS_STRING(self), *sub; | |
| 2458 | 2441 | PyObject *list, *str, *subobj = Py_None; | |
@@ -2489,17 +2472,13 @@ bytearray_rsplit(PyByteArrayObject *self, PyObject *args) | |||
| 2489 | 2472 | } | |
| 2490 | 2473 | ||
| 2491 | 2474 | j = len; | |
| 2492 | - i = j - n; | ||
| 2493 | - | ||
| 2494 | - while ( (i >= 0) && (maxsplit-- > 0) ) { | ||
| 2495 | - for (; i>=0; i--) { | ||
| 2496 | - if (Py_STRING_MATCH(s, i, sub, n)) { | ||
| 2497 | - SPLIT_ADD(s, i + n, j); | ||
| 2498 | - j = i; | ||
| 2499 | - i -= n; | ||
| 2500 | - break; | ||
| 2501 | - } | ||
| 2502 | - } | ||
| 2475 | + | ||
| 2476 | + while (maxsplit-- > 0) { | ||
| 2477 | + pos = fastsearch(s, j, sub, n, FAST_RSEARCH); | ||
| 2478 | + if (pos < 0) | ||
| 2479 | + break; | ||
| 2480 | + SPLIT_ADD(s, pos + n, j); | ||
| 2481 | + j = pos; | ||
| 2503 | 2482 | } | |
| 2504 | 2483 | SPLIT_ADD(s, 0, j); | |
| 2505 | 2484 | FIX_PREALLOC_SIZE(list); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,10 +15,6 @@ STRINGLIB_EMPTY | |||
| 15 | 15 | ||
| 16 | 16 | a PyObject representing the empty string | |
| 17 | 17 | ||
| 18 | - int STRINGLIB_CMP(STRINGLIB_CHAR*, STRINGLIB_CHAR*, Py_ssize_t) | ||
| 19 | - | ||
| 20 | - compares two strings. returns 0 if they match, and non-zero if not. | ||
| 21 | - | ||
| 22 | 18 | Py_ssize_t STRINGLIB_LEN(PyObject*) | |
| 23 | 19 | ||
| 24 | 20 | returns the length of the given string object (which must be of the | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,7 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | 6 | /* fast search/count implementation, based on a mix between boyer- | |
| 7 | 7 | moore and horspool, with a few more bells and whistles on the top. | |
| 8 | - for some more background, see: http://effbot.org/stringlib.htm */ | ||
| 8 | + for some more background, see: http://effbot.org/zone/stringlib.htm */ | ||
| 9 | 9 | ||
| 10 | 10 | /* note: fastsearch may access s[n], which isn't a problem when using | |
| 11 | 11 | Python's ordinary string types, but may cause problems if you're | |
@@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | 17 | #define FAST_COUNT 0 | |
| 18 | 18 | #define FAST_SEARCH 1 | |
| 19 | + #define FAST_RSEARCH 2 | ||
| 19 | 20 | ||
| 20 | 21 | Py_LOCAL_INLINE(Py_ssize_t) | |
| 21 | 22 | fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, | |
@@ -41,51 +42,92 @@ fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, | |||
| 41 | 42 | if (s[i] == p[0]) | |
| 42 | 43 | count++; | |
| 43 | 44 | return count; | |
| 44 | - } else { | ||
| 45 | + } else if (mode == FAST_SEARCH) { | ||
| 45 | 46 | for (i = 0; i < n; i++) | |
| 46 | 47 | if (s[i] == p[0]) | |
| 47 | 48 | return i; | |
| 49 | + } else { /* FAST_RSEARCH */ | ||
| 50 | + for (i = n - 1; i > -1; i--) | ||
| 51 | + if (s[i] == p[0]) | ||
| 52 | + return i; | ||
| 48 | 53 | } | |
| 49 | 54 | return -1; | |
| 50 | 55 | } | |
| 51 | 56 | ||
| 52 | 57 | mlast = m - 1; | |
| 53 | - | ||
| 54 | - /* create compressed boyer-moore delta 1 table */ | ||
| 55 | 58 | skip = mlast - 1; | |
| 56 | - /* process pattern[:-1] */ | ||
| 57 | - for (mask = i = 0; i < mlast; i++) { | ||
| 58 | - mask |= (1 << (p[i] & 0x1F)); | ||
| 59 | - if (p[i] == p[mlast]) | ||
| 60 | - skip = mlast - i - 1; | ||
| 61 | - } | ||
| 62 | - /* process pattern[-1] outside the loop */ | ||
| 63 | - mask |= (1 << (p[mlast] & 0x1F)); | ||
| 64 | - | ||
| 65 | - for (i = 0; i <= w; i++) { | ||
| 66 | - /* note: using mlast in the skip path slows things down on x86 */ | ||
| 67 | - if (s[i+m-1] == p[m-1]) { | ||
| 68 | - /* candidate match */ | ||
| 69 | - for (j = 0; j < mlast; j++) | ||
| 70 | - if (s[i+j] != p[j]) | ||
| 71 | - break; | ||
| 72 | - if (j == mlast) { | ||
| 73 | - /* got a match! */ | ||
| 74 | - if (mode != FAST_COUNT) | ||
| 59 | + | ||
| 60 | + if (mode != FAST_RSEARCH) { | ||
| 61 | + | ||
| 62 | + /* create compressed boyer-moore delta 1 table */ | ||
| 63 | + | ||
| 64 | + /* process pattern[:-1] */ | ||
| 65 | + for (mask = i = 0; i < mlast; i++) { | ||
| 66 | + mask |= (1 << (p[i] & 0x1F)); | ||
| 67 | + if (p[i] == p[mlast]) | ||
| 68 | + skip = mlast - i - 1; | ||
| 69 | + } | ||
| 70 | + /* process pattern[-1] outside the loop */ | ||
| 71 | + mask |= (1 << (p[mlast] & 0x1F)); | ||
| 72 | + | ||
| 73 | + for (i = 0; i <= w; i++) { | ||
| 74 | + /* note: using mlast in the skip path slows things down on x86 */ | ||
| 75 | + if (s[i+m-1] == p[m-1]) { | ||
| 76 | + /* candidate match */ | ||
| 77 | + for (j = 0; j < mlast; j++) | ||
| 78 | + if (s[i+j] != p[j]) | ||
| 79 | + break; | ||
| 80 | + if (j == mlast) { | ||
| 81 | + /* got a match! */ | ||
| 82 | + if (mode != FAST_COUNT) | ||
| 83 | + return i; | ||
| 84 | + count++; | ||
| 85 | + i = i + mlast; | ||
| 86 | + continue; | ||
| 87 | + } | ||
| 88 | + /* miss: check if next character is part of pattern */ | ||
| 89 | + if (!(mask & (1 << (s[i+m] & 0x1F)))) | ||
| 90 | + i = i + m; | ||
| 91 | + else | ||
| 92 | + i = i + skip; | ||
| 93 | + } else { | ||
| 94 | + /* skip: check if next character is part of pattern */ | ||
| 95 | + if (!(mask & (1 << (s[i+m] & 0x1F)))) | ||
| 96 | + i = i + m; | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + } else { /* FAST_RSEARCH */ | ||
| 100 | + | ||
| 101 | + /* create compressed boyer-moore delta 1 table */ | ||
| 102 | + | ||
| 103 | + /* process pattern[0] outside the loop */ | ||
| 104 | + mask = (1 << (p[0] & 0x1F)); | ||
| 105 | + /* process pattern[:0:-1] */ | ||
| 106 | + for (i = mlast; i > 0; i--) { | ||
| 107 | + mask |= (1 << (p[i] & 0x1F)); | ||
| 108 | + if (p[i] == p[0]) | ||
| 109 | + skip = i - 1; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + for (i = w; i >= 0; i--) { | ||
| 113 | + if (s[i] == p[0]) { | ||
| 114 | + /* candidate match */ | ||
| 115 | + for (j = mlast; j > 0; j--) | ||
| 116 | + if (s[i+j] != p[j]) | ||
| 117 | + break; | ||
| 118 | + if (j == 0) | ||
| 119 | + /* got a match! */ | ||
| 75 | 120 | return i; | |
| 76 | - count++; | ||
| 77 | - i = i + mlast; | ||
| 78 | - continue; | ||
| 121 | + /* miss: check if previous character is part of pattern */ | ||
| 122 | + if (!(mask & (1 << (s[i-1] & 0x1F)))) | ||
| 123 | + i = i - m; | ||
| 124 | + else | ||
| 125 | + i = i - skip; | ||
| 126 | + } else { | ||
| 127 | + /* skip: check if previous character is part of pattern */ | ||
| 128 | + if (!(mask & (1 << (s[i-1] & 0x1F)))) | ||
| 129 | + i = i - m; | ||
| 79 | 130 | } | |
| 80 | - /* miss: check if next character is part of pattern */ | ||
| 81 | - if (!(mask & (1 << (s[i+m] & 0x1F)))) | ||
| 82 | - i = i + m; | ||
| 83 | - else | ||
| 84 | - i = i + skip; | ||
| 85 | - } else { | ||
| 86 | - /* skip: check if next character is part of pattern */ | ||
| 87 | - if (!(mask & (1 << (s[i+m] & 0x1F)))) | ||
| 88 | - i = i + m; | ||
| 89 | 131 | } | |
| 90 | 132 | } | |
| 91 | 133 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -32,20 +32,19 @@ stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, | |||
| 32 | 32 | const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, | |
| 33 | 33 | Py_ssize_t offset) | |
| 34 | 34 | { | |
| 35 | - /* XXX - create reversefastsearch helper! */ | ||
| 36 | - if (sub_len == 0) { | ||
| 37 | - if (str_len < 0) | ||
| 38 | - return -1; | ||
| 39 | - return str_len + offset; | ||
| 40 | - } else { | ||
| 41 | - Py_ssize_t j, pos = -1; | ||
| 42 | - for (j = str_len - sub_len; j >= 0; --j) | ||
| 43 | - if (STRINGLIB_CMP(str+j, sub, sub_len) == 0) { | ||
| 44 | - pos = j + offset; | ||
| 45 | - break; | ||
| 46 | - } | ||
| 47 | - return pos; | ||
| 48 | - } | ||
| 35 | + Py_ssize_t pos; | ||
| 36 | + | ||
| 37 | + if (str_len < 0) | ||
| 38 | + return -1; | ||
| 39 | + if (sub_len == 0) | ||
| 40 | + return str_len + offset; | ||
| 41 | + | ||
| 42 | + pos = fastsearch(str, str_len, sub, sub_len, FAST_RSEARCH); | ||
| 43 | + | ||
| 44 | + if (pos >= 0) | ||
| 45 | + pos += offset; | ||
| 46 | + | ||
| 47 | + return pos; | ||
| 49 | 48 | } | |
| 50 | 49 | ||
| 51 | 50 | Py_LOCAL_INLINE(Py_ssize_t) | |
@@ -64,10 +63,7 @@ stringlib_find_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, | |||
| 64 | 63 | if (end < 0) | |
| 65 | 64 | end = 0; | |
| 66 | 65 | ||
| 67 | - return stringlib_find( | ||
| 68 | - str + start, end - start, | ||
| 69 | - sub, sub_len, start | ||
| 70 | - ); | ||
| 66 | + return stringlib_find(str + start, end - start, sub, sub_len, start); | ||
| 71 | 67 | } | |
| 72 | 68 | ||
| 73 | 69 | Py_LOCAL_INLINE(Py_ssize_t) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -58,7 +58,7 @@ stringlib_rpartition( | |||
| 58 | 58 | ) | |
| 59 | 59 | { | |
| 60 | 60 | PyObject* out; | |
| 61 | - Py_ssize_t pos, j; | ||
| 61 | + Py_ssize_t pos; | ||
| 62 | 62 | ||
| 63 | 63 | if (sep_len == 0) { | |
| 64 | 64 | PyErr_SetString(PyExc_ValueError, "empty separator"); | |
@@ -69,20 +69,14 @@ stringlib_rpartition( | |||
| 69 | 69 | if (!out) | |
| 70 | 70 | return NULL; | |
| 71 | 71 | ||
| 72 | - /* XXX - create reversefastsearch helper! */ | ||
| 73 | - pos = -1; | ||
| 74 | - for (j = str_len - sep_len; j >= 0; --j) | ||
| 75 | - if (STRINGLIB_CMP(str+j, sep, sep_len) == 0) { | ||
| 76 | - pos = j; | ||
| 77 | - break; | ||
| 78 | - } | ||
| 72 | + pos = fastsearch(str, str_len, sep, sep_len, FAST_RSEARCH); | ||
| 79 | 73 | ||
| 80 | 74 | if (pos < 0) { | |
| 81 | 75 | Py_INCREF(STRINGLIB_EMPTY); | |
| 82 | 76 | PyTuple_SET_ITEM(out, 0, (PyObject*) STRINGLIB_EMPTY); | |
| 83 | 77 | Py_INCREF(STRINGLIB_EMPTY); | |
| 84 | 78 | PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY); | |
| 85 | - Py_INCREF(str_obj); | ||
| 79 | + Py_INCREF(str_obj); | ||
| 86 | 80 | PyTuple_SET_ITEM(out, 2, (PyObject*) str_obj); | |
| 87 | 81 | return out; | |
| 88 | 82 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,7 +22,6 @@ | |||
| 22 | 22 | #define STRINGLIB_RESIZE _PyBytes_Resize | |
| 23 | 23 | #define STRINGLIB_CHECK PyBytes_Check | |
| 24 | 24 | #define STRINGLIB_CHECK_EXACT PyBytes_CheckExact | |
| 25 | - #define STRINGLIB_CMP memcmp | ||
| 26 | 25 | #define STRINGLIB_TOSTR PyObject_Str | |
| 27 | 26 | #define STRINGLIB_GROUPING _PyBytes_InsertThousandsGrouping | |
| 28 | 27 | #define STRINGLIB_GROUPING_LOCALE _PyBytes_InsertThousandsGroupingLocale | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -35,23 +35,4 @@ | |||
| 35 | 35 | ||
| 36 | 36 | #define STRINGLIB_WANT_CONTAINS_OBJ 1 | |
| 37 | 37 | ||
| 38 | - /* STRINGLIB_CMP was defined as: | ||
| 39 | - | ||
| 40 | - Py_LOCAL_INLINE(int) | ||
| 41 | - STRINGLIB_CMP(const Py_UNICODE* str, const Py_UNICODE* other, Py_ssize_t len) | ||
| 42 | - { | ||
| 43 | - if (str[0] != other[0]) | ||
| 44 | - return 1; | ||
| 45 | - return memcmp((void*) str, (void*) other, len * sizeof(Py_UNICODE)); | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - but unfortunately that gives a error if the function isn't used in a file that | ||
| 49 | - includes this file. So, reluctantly convert it to a macro instead. */ | ||
| 50 | - | ||
| 51 | - #define STRINGLIB_CMP(str, other, len) \ | ||
| 52 | - (((str)[0] != (other)[0]) ? \ | ||
| 53 | - 1 : \ | ||
| 54 | - memcmp((void*) (str), (void*) (other), (len) * sizeof(Py_UNICODE))) | ||
| 55 | - | ||
| 56 | - | ||
| 57 | 38 | #endif /* !STRINGLIB_UNICODEDEFS_H */ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments