Skip to content

Commit 12a9a35

Browse files
committed
gh-153569: speed up UTF-8 readline decoding
1 parent dea35e4 commit 12a9a35

3 files changed

Lines changed: 25 additions & 10 deletions

File tree

Parser/tokenizer/decoder.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,10 @@ _PyTok_DetectEncoding(struct tok_state *tok, const _PyTok_Chunk *first,
267267

268268
int
269269
_PyTok_DecodeOnce(struct tok_state *tok, _PyTok_Chunk *chunk,
270-
const char *encoding)
270+
const char *encoding, const char *errors)
271271
{
272272
PyObject *unicode = PyUnicode_Decode(
273-
chunk->data, chunk->len, encoding, NULL);
273+
chunk->data, chunk->len, encoding, errors);
274274
if (unicode == NULL) {
275275
tok->done = PyErr_ExceptionMatches(PyExc_MemoryError)
276276
? E_NOMEM : E_DECODE;
@@ -387,7 +387,8 @@ _PyTok_PrepareString(struct tok_state *tok, const char *input, int utf8_only,
387387
.ownership = _PYTOK_CHUNK_BORROWED,
388388
};
389389
if (tok->encoding != NULL && strcmp(tok->encoding, "utf-8") != 0) {
390-
if (_PyTok_DecodeOnce(tok, &decoded, tok->encoding) < 0) {
390+
if (_PyTok_DecodeOnce(
391+
tok, &decoded, tok->encoding, NULL) < 0) {
391392
return -1;
392393
}
393394
}

Parser/tokenizer/reader.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,12 +381,11 @@ next_readline(struct tok_state *tok, _PyTok_Chunk *chunk)
381381
Py_DECREF(raw);
382382
return _PYTOK_READ_ERROR;
383383
}
384-
if (_PyTok_StartDecoder(tok, "replace") < 0) {
385-
Py_XDECREF(raw);
386-
return _PYTOK_READ_ERROR;
387-
}
388384
if (PyBytes_GET_SIZE(raw) == 0) {
389385
Py_DECREF(raw);
386+
if (_PyTok_StartDecoder(tok, "replace") < 0) {
387+
return _PYTOK_READ_ERROR;
388+
}
390389
if (finalize_decoding(tok) < 0) {
391390
return _PYTOK_READ_ERROR;
392391
}
@@ -396,7 +395,20 @@ next_readline(struct tok_state *tok, _PyTok_Chunk *chunk)
396395
input.data = PyBytes_AS_STRING(raw);
397396
input.len = PyBytes_GET_SIZE(raw);
398397
input.ownership = _PYTOK_CHUNK_PYOBJECT;
399-
if (_PyTok_DecodeChunk(tok, &input, 0) < 0) {
398+
int decoded;
399+
if (reader->decoder == NULL &&
400+
strcmp(tok->encoding, "utf-8") == 0 &&
401+
chunk_is_line(&input)) {
402+
decoded = _PyTok_DecodeOnce(
403+
tok, &input, "utf-8", "replace");
404+
}
405+
else {
406+
decoded = _PyTok_StartDecoder(tok, "replace");
407+
if (decoded == 0) {
408+
decoded = _PyTok_DecodeChunk(tok, &input, 0);
409+
}
410+
}
411+
if (decoded < 0) {
400412
_PyTok_ChunkClear(&input);
401413
return _PYTOK_READ_ERROR;
402414
}
@@ -482,7 +494,8 @@ next_interactive(struct tok_state *tok, _PyTok_Chunk *chunk)
482494
.ownership = _PYTOK_CHUNK_PYMEM,
483495
};
484496
if (tok->encoding != NULL &&
485-
_PyTok_DecodeOnce(tok, &decoded, tok->encoding) < 0) {
497+
_PyTok_DecodeOnce(
498+
tok, &decoded, tok->encoding, NULL) < 0) {
486499
_PyTok_ChunkClear(&decoded);
487500
return _PYTOK_READ_ERROR;
488501
}

Parser/tokenizer/reader_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ typedef struct _PyTok_Reader {
6464
struct tok_state;
6565

6666
char *_PyTok_CopyBytes(const char *, Py_ssize_t);
67-
int _PyTok_DecodeOnce(struct tok_state *, _PyTok_Chunk *, const char *);
67+
int _PyTok_DecodeOnce(
68+
struct tok_state *, _PyTok_Chunk *, const char *, const char *);
6869
char *_PyTok_NormalizeNewlines(
6970
const char *, Py_ssize_t, int, int, Py_ssize_t *, int *);
7071
void _PyTok_ChunkClear(_PyTok_Chunk *);

0 commit comments

Comments
 (0)