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

Skip to content

Commit f645451

Browse files
committed
Issue #11856: Speed up parsing of JSON numbers.
1 parent 54afa55 commit f645451

2 files changed

Lines changed: 33 additions & 15 deletions

File tree

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ Core and Builtins
113113
Library
114114
-------
115115

116+
- Issue #11856: Speed up parsing of JSON numbers.
117+
116118
- Issue #11005: threading.RLock()._release_save() raises a RuntimeError if the
117119
lock was not acquired.
118120

Modules/_json.c

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,8 @@ _match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_
842842
Py_ssize_t idx = start;
843843
int is_float = 0;
844844
PyObject *rval;
845-
PyObject *numstr;
845+
PyObject *numstr = NULL;
846+
PyObject *custom_func;
846847

847848
/* read a sign if it's there, make sure it's not the end of the string */
848849
if (str[idx] == '-') {
@@ -895,22 +896,37 @@ _match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_
895896
}
896897
}
897898

898-
/* copy the section we determined to be a number */
899-
numstr = PyUnicode_FromUnicode(&str[start], idx - start);
900-
if (numstr == NULL)
901-
return NULL;
902-
if (is_float) {
903-
/* parse as a float using a fast path if available, otherwise call user defined method */
904-
if (s->parse_float != (PyObject *)&PyFloat_Type) {
905-
rval = PyObject_CallFunctionObjArgs(s->parse_float, numstr, NULL);
906-
}
907-
else {
908-
rval = PyFloat_FromString(numstr);
909-
}
899+
if (is_float && s->parse_float != (PyObject *)&PyFloat_Type)
900+
custom_func = s->parse_float;
901+
else if (!is_float && s->parse_int != (PyObject *) &PyLong_Type)
902+
custom_func = s->parse_int;
903+
else
904+
custom_func = NULL;
905+
906+
if (custom_func) {
907+
/* copy the section we determined to be a number */
908+
numstr = PyUnicode_FromUnicode(&str[start], idx - start);
909+
if (numstr == NULL)
910+
return NULL;
911+
rval = PyObject_CallFunctionObjArgs(custom_func, numstr, NULL);
910912
}
911913
else {
912-
/* no fast path for unicode -> int, just call */
913-
rval = PyObject_CallFunctionObjArgs(s->parse_int, numstr, NULL);
914+
Py_ssize_t i, n;
915+
char *buf;
916+
/* Straight conversion to ASCII, to avoid costly conversion of
917+
decimal unicode digits (which cannot appear here) */
918+
n = idx - start;
919+
numstr = PyBytes_FromStringAndSize(NULL, n);
920+
if (numstr == NULL)
921+
return NULL;
922+
buf = PyBytes_AS_STRING(numstr);
923+
for (i = 0; i < n; i++) {
924+
buf[i] = (char) str[i + start];
925+
}
926+
if (is_float)
927+
rval = PyFloat_FromString(numstr);
928+
else
929+
rval = PyLong_FromString(buf, NULL, 10);
914930
}
915931
Py_DECREF(numstr);
916932
*next_idx_ptr = idx;

0 commit comments

Comments
 (0)