@@ -1293,63 +1293,68 @@ static bool _needs_escaping[256]
1293
1293
static char _hex[17 ] = " 0123456789abcdef" ; // really only needs to be 16 but clang will complain
1294
1294
1295
1295
extern " C" PyObject* PyString_Repr (PyObject* obj, int smartquotes) noexcept {
1296
- BoxedString* self = (BoxedString*)obj;
1297
- assert (PyString_Check (self));
1298
-
1299
- std::ostringstream os (" " );
1300
-
1301
- llvm::StringRef s (self->s ());
1302
- char quote = ' \' ' ;
1303
- if (smartquotes && s.find (' \' ' , 0 ) != std::string::npos && s.find (' \" ' , 0 ) == std::string::npos) {
1304
- quote = ' \" ' ;
1296
+ BoxedString* op = (BoxedString*)obj;
1297
+ size_t newsize = 2 + 4 * Py_SIZE (op);
1298
+ PyObject* v;
1299
+ if (newsize > PY_SSIZE_T_MAX || newsize / 4 != Py_SIZE (op)) {
1300
+ PyErr_SetString (PyExc_OverflowError, " string is too large to make repr" );
1301
+ return NULL ;
1305
1302
}
1306
- os << quote;
1307
- for (int i = 0 ; i < s.size (); i++) {
1308
- char c = s[i];
1309
- if ((c == ' \' ' && quote == ' \" ' ) || !_needs_escaping[c & 0xff ]) {
1310
- os << c;
1311
- } else {
1312
- char special = 0 ;
1313
- switch (c) {
1314
- case ' \t ' :
1315
- special = ' t' ;
1316
- break ;
1317
- case ' \n ' :
1318
- special = ' n' ;
1319
- break ;
1320
- case ' \r ' :
1321
- special = ' r' ;
1322
- break ;
1323
- case ' \' ' :
1324
- special = ' \' ' ;
1325
- break ;
1326
- case ' \" ' :
1327
- special = ' \" ' ;
1328
- break ;
1329
- case ' \\ ' :
1330
- special = ' \\ ' ;
1331
- break ;
1332
- }
1333
- if (special) {
1334
- os << ' \\ ' ;
1335
- os << special;
1336
- } else {
1337
- os << ' \\ ' ;
1338
- os << ' x' ;
1339
- os << _hex[(c & 0xff ) / 16 ];
1340
- os << _hex[(c & 0xff ) % 16 ];
1341
- }
1303
+ v = PyString_FromStringAndSize ((char *)NULL , newsize);
1304
+ if (v == NULL ) {
1305
+ return NULL ;
1306
+ } else {
1307
+ Py_ssize_t i;
1308
+ char c;
1309
+ char * p;
1310
+ int quote;
1311
+
1312
+ /* figure out which quote to use; single is preferred */
1313
+ quote = ' \' ' ;
1314
+ if (smartquotes && memchr (op->data (), ' \' ' , Py_SIZE (op)) && !memchr (op->data (), ' "' , Py_SIZE (op)))
1315
+ quote = ' "' ;
1316
+
1317
+ p = PyString_AS_STRING (v);
1318
+ *p++ = quote;
1319
+ for (i = 0 ; i < Py_SIZE (op); i++) {
1320
+ /* There's at least enough room for a hex escape
1321
+ * and a closing quote. */
1322
+ assert (newsize - (p - PyString_AS_STRING (v)) >= 5 );
1323
+ c = op->data ()[i];
1324
+ if (c == quote || c == ' \\ ' )
1325
+ *p++ = ' \\ ' , *p++ = c;
1326
+ else if (c == ' \t ' )
1327
+ *p++ = ' \\ ' , *p++ = ' t' ;
1328
+ else if (c == ' \n ' )
1329
+ *p++ = ' \\ ' , *p++ = ' n' ;
1330
+ else if (c == ' \r ' )
1331
+ *p++ = ' \\ ' , *p++ = ' r' ;
1332
+ else if (c < ' ' || c >= 0x7f ) {
1333
+ /* For performance, we don't want to call
1334
+ * PyOS_snprintf here (extra layers of
1335
+ * function call). */
1336
+ sprintf (p, " \\ x%02x" , c & 0xff );
1337
+ p += 4 ;
1338
+ } else
1339
+ *p++ = c;
1342
1340
}
1341
+ assert (newsize - (p - PyString_AS_STRING (v)) >= 1 );
1342
+ *p++ = quote;
1343
+ *p = ' \0 ' ;
1344
+ if (_PyString_Resize (&v, (p - PyString_AS_STRING (v))))
1345
+ return NULL ;
1346
+ return v;
1343
1347
}
1344
- os << quote;
1345
-
1346
- return boxString (os.str ());
1347
1348
}
1348
1349
1349
1350
extern " C" Box* strRepr (BoxedString* self) {
1350
1351
return PyString_Repr (self, 1 /* smartquotes */ );
1351
1352
}
1352
1353
1354
+ extern " C" Box* str_repr (Box* self) noexcept {
1355
+ return PyString_Repr (self, 1 /* smartquotes */ );
1356
+ }
1357
+
1353
1358
/* Unescape a backslash-escaped string. If unicode is non-zero,
1354
1359
the string is a u-literal. If recode_encoding is non-zero,
1355
1360
the string is UTF-8 encoded and should be re-encoded in the
@@ -2882,6 +2887,7 @@ void setupStr() {
2882
2887
add_operators (str_cls);
2883
2888
str_cls->freeze ();
2884
2889
2890
+ str_cls->tp_repr = str_repr;
2885
2891
str_cls->tp_iter = (decltype (str_cls->tp_iter ))strIter;
2886
2892
str_cls->tp_hash = (hashfunc)str_hash;
2887
2893
str_cls->tp_as_sequence ->sq_length = str_length;
0 commit comments