]> granicus.if.org Git - python/commitdiff
Issue #6713: Improve decimal int -> string conversions. Thanks Gawain
authorMark Dickinson <dickinsm@gmail.com>
Sun, 27 Sep 2009 16:05:21 +0000 (16:05 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Sun, 27 Sep 2009 16:05:21 +0000 (16:05 +0000)
Bolton for the suggestion and original patches.

Misc/NEWS
Objects/intobject.c

index 15db19963ec3354ae0b7d06edcd3d368c55f61c9..e742ffccee5171d66f5c1a923b2a3bc384fed1c1 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -18,7 +18,8 @@ Core and Builtins
 - Issue #6922: Fix an infinite loop when trying to decode an invalid
   UTF-32 stream with a non-raising error handler like "replace" or "ignore".
 
-- Issue #6713: Improve performance of integer -> string conversions.
+- Issue #6713: Improve performance of base 10 int -> string and
+  long -> string conversions.
 
 - Issue #1590864: Fix potential deadlock when mixing threads and fork().
 
index a0e60e756f41bd094fe11b0f3c3500e0f54aea1e..8a8972c711dacfc00cd6a937bdf4543821b11572 100644 (file)
@@ -436,12 +436,6 @@ int_print(PyIntObject *v, FILE *fp, int flags)
        return 0;
 }
 
-static PyObject *
-int_repr(PyIntObject *v)
-{
-       return _PyInt_Format(v, 10, 0);
-}
-
 static int
 int_compare(PyIntObject *v, PyIntObject *w)
 {
@@ -1113,6 +1107,26 @@ int_get1(PyIntObject *v, void *context) {
        return PyInt_FromLong(1L);
 }
 
+/* Convert an integer to a decimal string.  On many platforms, this
+   will be significantly faster than the general arbitrary-base
+   conversion machinery in _PyInt_Format, thanks to optimization
+   opportunities offered by division by a compile-time constant. */
+static PyObject *
+int_to_decimal_string(PyIntObject *v) {
+       char buf[sizeof(long)*CHAR_BIT/3+6], *p, *bufend;
+       long n = v->ob_ival;
+       unsigned long absn;
+       p = bufend = buf + sizeof(buf);
+       absn = n < 0 ? -(unsigned long)n : n;
+       do {
+               *--p = '0' + absn % 10;
+               absn /= 10;
+       } while (absn);
+       if (n < 0)
+               *--p = '-';
+       return PyString_FromStringAndSize(p, bufend - p);
+}
+
 /* Convert an integer to the given base.  Returns a string.
    If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'.
    If newstyle is zero, then use the pre-2.6 behavior of octal having
@@ -1137,6 +1151,10 @@ _PyInt_Format(PyIntObject *v, int base, int newstyle)
 
        assert(base >= 2 && base <= 36);
 
+       /* Special case base 10, for speed */
+       if (base == 10)
+               return int_to_decimal_string(v);
+
        do {
                /* I'd use i_divmod, except it doesn't produce the results
                   I want when n is negative.  So just duplicate the salient
@@ -1169,7 +1187,7 @@ _PyInt_Format(PyIntObject *v, int base, int newstyle)
                *--p = 'x';
                *--p = '0';
        }
-       else if (base != 10) {
+       else {
                *--p = '#';
                *--p = '0' + base%10;
                if (base > 10)
@@ -1341,13 +1359,13 @@ PyTypeObject PyInt_Type = {
        0,                                      /* tp_getattr */
        0,                                      /* tp_setattr */
        (cmpfunc)int_compare,                   /* tp_compare */
-       (reprfunc)int_repr,                     /* tp_repr */
+       (reprfunc)int_to_decimal_string,        /* tp_repr */
        &int_as_number,                         /* tp_as_number */
        0,                                      /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
        (hashfunc)int_hash,                     /* tp_hash */
-        0,                                     /* tp_call */
-        (reprfunc)int_repr,                    /* tp_str */
+       0,                                      /* tp_call */
+       (reprfunc)int_to_decimal_string,        /* tp_str */
        PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */