Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8fa5dd0

Browse files
committed
More bug 460020: lots of string optimizations inhibited for string
subclasses, all "the usual" ones (slicing etc), plus replace, translate, ljust, rjust, center and strip. I don't know how to be sure they've all been caught. Question: Should we complain if someone tries to intern an instance of a string subclass? I hate to slow any code on those paths.
1 parent ee0fe0b commit 8fa5dd0

2 files changed

Lines changed: 71 additions & 81 deletions

File tree

Lib/test/test_descr.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,9 +1481,32 @@ def rev(self):
14811481
verify(str(s) == "12345")
14821482
verify(str(s).__class__ is str)
14831483

1484-
s = madstring("\x00" * 5)
1485-
verify(str(s) == "\x00" * 5)
1484+
base = "\x00" * 5
1485+
s = madstring(base)
1486+
verify(str(s) == base)
14861487
verify(str(s).__class__ is str)
1488+
verify((s + "").__class__ is str)
1489+
verify(("" + s).__class__ is str)
1490+
verify((s * 0).__class__ is str)
1491+
verify((s * 1).__class__ is str)
1492+
verify((s * 2).__class__ is str)
1493+
verify(s[:].__class__ is str)
1494+
verify(s[0:0].__class__ is str)
1495+
verify(s.strip().__class__ is str)
1496+
identitytab = ''.join([chr(i) for i in range(256)])
1497+
verify(s.translate(identitytab).__class__ is str)
1498+
verify(s.translate(identitytab) == base)
1499+
verify(s.translate(identitytab, "x").__class__ is str)
1500+
verify(s.translate(identitytab, "x") == base)
1501+
verify(s.translate(identitytab, "\x00") == "")
1502+
verify(s.replace("x", "x").__class__ is str)
1503+
verify(s.replace("x", "x") == base)
1504+
verify(s.ljust(len(s)).__class__ is str)
1505+
verify(s.ljust(len(s)) == base)
1506+
verify(s.rjust(len(s)).__class__ is str)
1507+
verify(s.rjust(len(s)) == base)
1508+
verify(s.center(len(s)).__class__ is str)
1509+
verify(s.center(len(s)) == base)
14871510

14881511
class madunicode(unicode):
14891512
_rev = None

Objects/stringobject.c

Lines changed: 46 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -673,11 +673,12 @@ string_concat(register PyStringObject *a, register PyObject *bb)
673673
}
674674
#define b ((PyStringObject *)bb)
675675
/* Optimize cases with empty left or right operand */
676-
if (a->ob_size == 0) {
677-
Py_INCREF(bb);
678-
return bb;
679-
}
680-
if (b->ob_size == 0) {
676+
if ((a->ob_size == 0 || b->ob_size == 0) &&
677+
PyString_CheckExact(a) && PyString_CheckExact(b)) {
678+
if (a->ob_size == 0) {
679+
Py_INCREF(bb);
680+
return bb;
681+
}
681682
Py_INCREF(a);
682683
return (PyObject *)a;
683684
}
@@ -719,7 +720,7 @@ string_repeat(register PyStringObject *a, register int n)
719720
"repeated string is too long");
720721
return NULL;
721722
}
722-
if (size == a->ob_size) {
723+
if (size == a->ob_size && PyString_CheckExact(a)) {
723724
Py_INCREF(a);
724725
return (PyObject *)a;
725726
}
@@ -759,7 +760,8 @@ string_slice(register PyStringObject *a, register int i, register int j)
759760
j = 0; /* Avoid signed/unsigned bug in next line */
760761
if (j > a->ob_size)
761762
j = a->ob_size;
762-
if (i == 0 && j == a->ob_size) { /* It's the same as a */
763+
if (i == 0 && j == a->ob_size && PyString_CheckExact(a)) {
764+
/* It's the same as a */
763765
Py_INCREF(a);
764766
return (PyObject *)a;
765767
}
@@ -1378,7 +1380,7 @@ do_strip(PyStringObject *self, int striptype)
13781380
j++;
13791381
}
13801382

1381-
if (i == 0 && j == len) {
1383+
if (i == 0 && j == len && PyString_CheckExact(self)) {
13821384
Py_INCREF(self);
13831385
return (PyObject*)self;
13841386
}
@@ -1735,7 +1737,7 @@ string_translate(PyStringObject *self, PyObject *args)
17351737
if (Py_CHARMASK((*output++ = table[c])) != c)
17361738
changed = 1;
17371739
}
1738-
if (changed)
1740+
if (changed || !PyString_CheckExact(input_obj))
17391741
return result;
17401742
Py_DECREF(result);
17411743
Py_INCREF(input_obj);
@@ -1755,7 +1757,7 @@ string_translate(PyStringObject *self, PyObject *args)
17551757
continue;
17561758
changed = 1;
17571759
}
1758-
if (!changed) {
1760+
if (!changed && PyString_CheckExact(input_obj)) {
17591761
Py_DECREF(result);
17601762
Py_INCREF(input_obj);
17611763
return input_obj;
@@ -1917,7 +1919,8 @@ string_replace(PyStringObject *self, PyObject *args)
19171919
{
19181920
const char *str = PyString_AS_STRING(self), *sub, *repl;
19191921
char *new_s;
1920-
int len = PyString_GET_SIZE(self), sub_len, repl_len, out_len;
1922+
const int len = PyString_GET_SIZE(self);
1923+
int sub_len, repl_len, out_len;
19211924
int count = -1;
19221925
PyObject *new;
19231926
PyObject *subobj, *replobj;
@@ -1960,9 +1963,16 @@ string_replace(PyStringObject *self, PyObject *args)
19601963
return NULL;
19611964
}
19621965
if (out_len == -1) {
1963-
/* we're returning another reference to self */
1964-
new = (PyObject*)self;
1965-
Py_INCREF(new);
1966+
if (PyString_CheckExact(self)) {
1967+
/* we're returning another reference to self */
1968+
new = (PyObject*)self;
1969+
Py_INCREF(new);
1970+
}
1971+
else {
1972+
new = PyString_FromStringAndSize(str, len);
1973+
if (new == NULL)
1974+
return NULL;
1975+
}
19661976
}
19671977
else {
19681978
new = PyString_FromStringAndSize(new_s, out_len);
@@ -2182,11 +2192,8 @@ string_expandtabs(PyStringObject *self, PyObject *args)
21822192
return u;
21832193
}
21842194

2185-
static
2186-
PyObject *pad(PyStringObject *self,
2187-
int left,
2188-
int right,
2189-
char fill)
2195+
static PyObject *
2196+
pad(PyStringObject *self, int left, int right, char fill)
21902197
{
21912198
PyObject *u;
21922199

@@ -2195,7 +2202,7 @@ PyObject *pad(PyStringObject *self,
21952202
if (right < 0)
21962203
right = 0;
21972204

2198-
if (left == 0 && right == 0) {
2205+
if (left == 0 && right == 0 && PyString_CheckExact(self)) {
21992206
Py_INCREF(self);
22002207
return (PyObject *)self;
22012208
}
@@ -2217,10 +2224,10 @@ PyObject *pad(PyStringObject *self,
22172224
}
22182225

22192226
static char ljust__doc__[] =
2220-
"S.ljust(width) -> string\n\
2221-
\n\
2222-
Return S left justified in a string of length width. Padding is\n\
2223-
done using spaces.";
2227+
"S.ljust(width) -> string\n"
2228+
"\n"
2229+
"Return S left justified in a string of length width. Padding is\n"
2230+
"done using spaces.";
22242231

22252232
static PyObject *
22262233
string_ljust(PyStringObject *self, PyObject *args)
@@ -2229,7 +2236,7 @@ string_ljust(PyStringObject *self, PyObject *args)
22292236
if (!PyArg_ParseTuple(args, "i:ljust", &width))
22302237
return NULL;
22312238

2232-
if (PyString_GET_SIZE(self) >= width) {
2239+
if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) {
22332240
Py_INCREF(self);
22342241
return (PyObject*) self;
22352242
}
@@ -2239,10 +2246,10 @@ string_ljust(PyStringObject *self, PyObject *args)
22392246

22402247

22412248
static char rjust__doc__[] =
2242-
"S.rjust(width) -> string\n\
2243-
\n\
2244-
Return S right justified in a string of length width. Padding is\n\
2245-
done using spaces.";
2249+
"S.rjust(width) -> string\n"
2250+
"\n"
2251+
"Return S right justified in a string of length width. Padding is\n"
2252+
"done using spaces.";
22462253

22472254
static PyObject *
22482255
string_rjust(PyStringObject *self, PyObject *args)
@@ -2251,7 +2258,7 @@ string_rjust(PyStringObject *self, PyObject *args)
22512258
if (!PyArg_ParseTuple(args, "i:rjust", &width))
22522259
return NULL;
22532260

2254-
if (PyString_GET_SIZE(self) >= width) {
2261+
if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) {
22552262
Py_INCREF(self);
22562263
return (PyObject*) self;
22572264
}
@@ -2261,10 +2268,10 @@ string_rjust(PyStringObject *self, PyObject *args)
22612268

22622269

22632270
static char center__doc__[] =
2264-
"S.center(width) -> string\n\
2265-
\n\
2266-
Return S centered in a string of length width. Padding is done\n\
2267-
using spaces.";
2271+
"S.center(width) -> string\n"
2272+
"\n"
2273+
"Return S centered in a string of length width. Padding is done\n"
2274+
"using spaces.";
22682275

22692276
static PyObject *
22702277
string_center(PyStringObject *self, PyObject *args)
@@ -2275,7 +2282,7 @@ string_center(PyStringObject *self, PyObject *args)
22752282
if (!PyArg_ParseTuple(args, "i:center", &width))
22762283
return NULL;
22772284

2278-
if (PyString_GET_SIZE(self) >= width) {
2285+
if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) {
22792286
Py_INCREF(self);
22802287
return (PyObject*) self;
22812288
}
@@ -2286,51 +2293,11 @@ string_center(PyStringObject *self, PyObject *args)
22862293
return pad(self, left, marg - left, ' ');
22872294
}
22882295

2289-
#if 0
2290-
static char zfill__doc__[] =
2291-
"S.zfill(width) -> string\n\
2292-
\n\
2293-
Pad a numeric string x with zeros on the left, to fill a field\n\
2294-
of the specified width. The string x is never truncated.";
2295-
2296-
static PyObject *
2297-
string_zfill(PyStringObject *self, PyObject *args)
2298-
{
2299-
int fill;
2300-
PyObject *u;
2301-
char *str;
2302-
2303-
int width;
2304-
if (!PyArg_ParseTuple(args, "i:zfill", &width))
2305-
return NULL;
2306-
2307-
if (PyString_GET_SIZE(self) >= width) {
2308-
Py_INCREF(self);
2309-
return (PyObject*) self;
2310-
}
2311-
2312-
fill = width - PyString_GET_SIZE(self);
2313-
2314-
u = pad(self, fill, 0, '0');
2315-
if (u == NULL)
2316-
return NULL;
2317-
2318-
str = PyString_AS_STRING(u);
2319-
if (str[fill] == '+' || str[fill] == '-') {
2320-
/* move sign to beginning of string */
2321-
str[0] = str[fill];
2322-
str[fill] = '0';
2323-
}
2324-
2325-
return u;
2326-
}
2327-
#endif
2328-
23292296
static char isspace__doc__[] =
2330-
"S.isspace() -> int\n\
2331-
\n\
2332-
Return 1 if there are only whitespace characters in S,\n\
2333-
0 otherwise.";
2297+
"S.isspace() -> int\n"
2298+
"\n"
2299+
"Return 1 if there are only whitespace characters in S,\n"
2300+
"0 otherwise.";
23342301

23352302
static PyObject*
23362303
string_isspace(PyStringObject *self)

0 commit comments

Comments
 (0)