[Python-checkins] cpython: Issue #11856: Speed up parsing of JSON numbers.

antoine.pitrou python-checkins at python.org
Mon Apr 25 19:16:19 CEST 2011


http://hg.python.org/cpython/rev/d60f9d9983bb
changeset:   69552:d60f9d9983bb
user:        Antoine Pitrou <solipsis at pitrou.net>
date:        Mon Apr 25 19:16:06 2011 +0200
summary:
  Issue #11856: Speed up parsing of JSON numbers.

files:
  Misc/NEWS       |   2 +
  Modules/_json.c |  46 ++++++++++++++++++++++++------------
  2 files changed, 33 insertions(+), 15 deletions(-)


diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -113,6 +113,8 @@
 Library
 -------
 
+- Issue #11856: Speed up parsing of JSON numbers.
+
 - Issue #11005: threading.RLock()._release_save() raises a RuntimeError if the
   lock was not acquired.
 
diff --git a/Modules/_json.c b/Modules/_json.c
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -842,7 +842,8 @@
     Py_ssize_t idx = start;
     int is_float = 0;
     PyObject *rval;
-    PyObject *numstr;
+    PyObject *numstr = NULL;
+    PyObject *custom_func;
 
     /* read a sign if it's there, make sure it's not the end of the string */
     if (str[idx] == '-') {
@@ -895,22 +896,37 @@
         }
     }
 
-    /* copy the section we determined to be a number */
-    numstr = PyUnicode_FromUnicode(&str[start], idx - start);
-    if (numstr == NULL)
-        return NULL;
-    if (is_float) {
-        /* parse as a float using a fast path if available, otherwise call user defined method */
-        if (s->parse_float != (PyObject *)&PyFloat_Type) {
-            rval = PyObject_CallFunctionObjArgs(s->parse_float, numstr, NULL);
-        }
-        else {
-            rval = PyFloat_FromString(numstr);
-        }
+    if (is_float && s->parse_float != (PyObject *)&PyFloat_Type)
+        custom_func = s->parse_float;
+    else if (!is_float && s->parse_int != (PyObject *) &PyLong_Type)
+        custom_func = s->parse_int;
+    else
+        custom_func = NULL;
+
+    if (custom_func) {
+        /* copy the section we determined to be a number */
+        numstr = PyUnicode_FromUnicode(&str[start], idx - start);
+        if (numstr == NULL)
+            return NULL;
+        rval = PyObject_CallFunctionObjArgs(custom_func, numstr, NULL);
     }
     else {
-        /* no fast path for unicode -> int, just call */
-        rval = PyObject_CallFunctionObjArgs(s->parse_int, numstr, NULL);
+        Py_ssize_t i, n;
+        char *buf;
+        /* Straight conversion to ASCII, to avoid costly conversion of
+           decimal unicode digits (which cannot appear here) */
+        n = idx - start;
+        numstr = PyBytes_FromStringAndSize(NULL, n);
+        if (numstr == NULL)
+            return NULL;
+        buf = PyBytes_AS_STRING(numstr);
+        for (i = 0; i < n; i++) {
+            buf[i] = (char) str[i + start];
+        }
+        if (is_float)
+            rval = PyFloat_FromString(numstr);
+        else
+            rval = PyLong_FromString(buf, NULL, 10);
     }
     Py_DECREF(numstr);
     *next_idx_ptr = idx;

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list