Skip to content

Commit 83499a4

Browse files
committed
Improve slow path
1 parent 078965b commit 83499a4

File tree

1 file changed

+38
-30
lines changed

1 file changed

+38
-30
lines changed

Modules/_json.c

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ typedef struct _PyEncoderObject {
5151
char sort_keys;
5252
char skipkeys;
5353
int allow_nan;
54-
PyObject * (*fast_encode)(PyObject *);
54+
int (*fast_encode)(PyUnicodeWriter *, PyObject *);
5555
} PyEncoderObject;
5656

5757
#define PyEncoderObject_CAST(op) ((PyEncoderObject *)(op))
@@ -103,6 +103,8 @@ _encoded_const(PyObject *obj);
103103
static void
104104
raise_errmsg(const char *msg, PyObject *s, Py_ssize_t end);
105105
static int
106+
_steal_accumulate(PyUnicodeWriter *writer, PyObject *stolen);
107+
static int
106108
encoder_write_string(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *obj);
107109
static PyObject *
108110
encoder_encode_float(PyEncoderObject *s, PyObject *obj);
@@ -209,8 +211,8 @@ ascii_escape_unicode(PyObject *pystr)
209211
return rval;
210212
}
211213

212-
static PyObject *
213-
ascii_escape_unicode_ex(PyObject *pystr)
214+
static int
215+
write_escaped_ascii(PyUnicodeWriter *writer, PyObject *pystr)
214216
{
215217
/* Take a PyUnicode pystr and return a new ASCII-only escaped PyUnicode */
216218
Py_ssize_t i;
@@ -227,7 +229,7 @@ ascii_escape_unicode_ex(PyObject *pystr)
227229
kind = PyUnicode_KIND(pystr);
228230

229231
/* Compute the output size */
230-
for (i = 0, output_size = 0; i < input_chars; i++) {
232+
for (i = 0, output_size = 2; i < input_chars; i++) {
231233
Py_UCS4 c = PyUnicode_READ(kind, input, i);
232234
Py_ssize_t d;
233235
if (S_CHAR(c)) {
@@ -244,22 +246,29 @@ ascii_escape_unicode_ex(PyObject *pystr)
244246
}
245247
if (output_size > PY_SSIZE_T_MAX - d) {
246248
PyErr_SetString(PyExc_OverflowError, "string is too long to escape");
247-
return NULL;
249+
return -1;
248250
}
249251
output_size += d;
250252
}
251253

252-
if (output_size == input_chars) {
254+
if (output_size == input_chars + 2) {
253255
/* No need to escape anything */
254-
return Py_NewRef(pystr);
256+
if (PyUnicodeWriter_WriteChar(writer, '"') < 0) {
257+
return -1;
258+
}
259+
if (PyUnicodeWriter_WriteStr(writer, pystr) < 0) {
260+
return -1;
261+
}
262+
return PyUnicodeWriter_WriteChar(writer, '"');
255263
}
256264

257265
rval = PyUnicode_New(output_size, 127);
258266
if (rval == NULL) {
259-
return NULL;
267+
return -1;
260268
}
261269
output = PyUnicode_1BYTE_DATA(rval);
262270
chars = 0;
271+
output[chars++] = '"';
263272
for (i = 0; i < input_chars; i++) {
264273
Py_UCS4 c = PyUnicode_READ(kind, input, i);
265274
if (S_CHAR(c)) {
@@ -269,10 +278,11 @@ ascii_escape_unicode_ex(PyObject *pystr)
269278
chars = ascii_escape_unichar(c, output, chars);
270279
}
271280
}
281+
output[chars++] = '"';
272282
#ifdef Py_DEBUG
273283
assert(_PyUnicode_CheckConsistency(rval, 1));
274284
#endif
275-
return rval;
285+
return _steal_accumulate(writer, rval);
276286
}
277287

278288
static PyObject *
@@ -369,8 +379,8 @@ escape_unicode(PyObject *pystr)
369379
return rval;
370380
}
371381

372-
static PyObject *
373-
escape_unicode_ex(PyObject *pystr)
382+
static int
383+
write_escaped_unicode(PyUnicodeWriter *writer, PyObject *pystr)
374384
{
375385
/* Take a PyUnicode pystr and return a new escaped PyUnicode */
376386
Py_ssize_t i;
@@ -388,7 +398,7 @@ escape_unicode_ex(PyObject *pystr)
388398
kind = PyUnicode_KIND(pystr);
389399

390400
/* Compute the output size */
391-
for (i = 0, output_size = 0; i < input_chars; i++) {
401+
for (i = 0, output_size = 2; i < input_chars; i++) {
392402
Py_UCS4 c = PyUnicode_READ(kind, input, i);
393403
Py_ssize_t d;
394404
switch (c) {
@@ -404,24 +414,31 @@ escape_unicode_ex(PyObject *pystr)
404414
}
405415
if (output_size > PY_SSIZE_T_MAX - d) {
406416
PyErr_SetString(PyExc_OverflowError, "string is too long to escape");
407-
return NULL;
417+
return -1;
408418
}
409419
output_size += d;
410420
}
411421

412-
if (output_size == input_chars) {
422+
if (output_size == input_chars + 2) {
413423
/* No need to escape anything */
414-
return Py_NewRef(pystr);
424+
if (PyUnicodeWriter_WriteChar(writer, '"') < 0) {
425+
return -1;
426+
}
427+
if (PyUnicodeWriter_WriteStr(writer, pystr) < 0) {
428+
return -1;
429+
}
430+
return PyUnicodeWriter_WriteChar(writer, '"');
415431
}
416432

417433
rval = PyUnicode_New(output_size, maxchar);
418434
if (rval == NULL)
419-
return NULL;
435+
return -1;
420436

421437
kind = PyUnicode_KIND(rval);
422438

423439
#define ENCODE_OUTPUT do { \
424440
chars = 0; \
441+
output[chars++] = '"'; \
425442
for (i = 0; i < input_chars; i++) { \
426443
Py_UCS4 c = PyUnicode_READ(kind, input, i); \
427444
switch (c) { \
@@ -445,6 +462,7 @@ escape_unicode_ex(PyObject *pystr)
445462
} \
446463
} \
447464
} \
465+
output[chars++] = '"'; \
448466
} while (0)
449467

450468
if (kind == PyUnicode_1BYTE_KIND) {
@@ -463,7 +481,7 @@ escape_unicode_ex(PyObject *pystr)
463481
#ifdef Py_DEBUG
464482
assert(_PyUnicode_CheckConsistency(rval, 1));
465483
#endif
466-
return rval;
484+
return _steal_accumulate(writer, rval);
467485
}
468486

469487
static void
@@ -1419,10 +1437,10 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
14191437
if (PyCFunction_Check(s->encoder)) {
14201438
PyCFunction f = PyCFunction_GetFunction(s->encoder);
14211439
if (f == py_encode_basestring_ascii) {
1422-
s->fast_encode = ascii_escape_unicode_ex;
1440+
s->fast_encode = write_escaped_ascii;
14231441
}
14241442
else if (f == py_encode_basestring) {
1425-
s->fast_encode = escape_unicode_ex;
1443+
s->fast_encode = write_escaped_unicode;
14261444
}
14271445
}
14281446

@@ -1619,17 +1637,7 @@ encoder_write_string(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *obj)
16191637
PyObject *encoded;
16201638

16211639
if (s->fast_encode) {
1622-
if (PyUnicodeWriter_WriteChar(writer, '"') < 0) {
1623-
return -1;
1624-
}
1625-
encoded = s->fast_encode(obj);
1626-
if (encoded == NULL) {
1627-
return -1;
1628-
}
1629-
if (_steal_accumulate(writer, encoded) < 0) {
1630-
return -1;
1631-
}
1632-
return PyUnicodeWriter_WriteChar(writer, '"');
1640+
return s->fast_encode(writer, obj);
16331641
}
16341642
encoded = PyObject_CallOneArg(s->encoder, obj);
16351643
if (encoded == NULL) {

0 commit comments

Comments
 (0)