]> granicus.if.org Git - python/commitdiff
Simplify and optimize formatlong()
authorVictor Stinner <victor.stinner@gmail.com>
Fri, 27 Apr 2012 21:40:13 +0000 (23:40 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Fri, 27 Apr 2012 21:40:13 +0000 (23:40 +0200)
 * Remove _PyBytes_FormatLong(): inline it into formatlong()
 * the input type is always a long, so remove the code for bool
 * don't duplicate the string if the length does not change
 * Use PyUnicode_DATA() instead of _PyUnicode_AsString()

Include/bytesobject.h
Objects/bytesobject.c
Objects/unicodeobject.c

index e1af89f9c95e980caff4a55a6edf32c94da8e54b..d7c7ffd37ba7847a44bc4f375a76ef69624f76e6 100644 (file)
@@ -62,8 +62,6 @@ PyAPI_FUNC(void) PyBytes_Concat(PyObject **, PyObject *);
 PyAPI_FUNC(void) PyBytes_ConcatAndDel(PyObject **, PyObject *);
 #ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyBytes_Resize(PyObject **, Py_ssize_t);
-PyAPI_FUNC(PyObject *) _PyBytes_FormatLong(PyObject*, int, int,
-                                                 int, char**, int*);
 #endif
 PyAPI_FUNC(PyObject *) PyBytes_DecodeEscape(const char *, Py_ssize_t,
                                                   const char *, Py_ssize_t,
index b07be26896fcd2c9589ffa2f50a65df7a1cf753d..efe6ef87b35a578b2549e923be7bc8678c2b1d7f 100644 (file)
@@ -2860,149 +2860,6 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
     return 0;
 }
 
-/* _PyBytes_FormatLong emulates the format codes d, u, o, x and X, and
- * the F_ALT flag, for Python's long (unbounded) ints.  It's not used for
- * Python's regular ints.
- * Return value:  a new PyBytes*, or NULL if error.
- *  .  *pbuf is set to point into it,
- *     *plen set to the # of chars following that.
- *     Caller must decref it when done using pbuf.
- *     The string starting at *pbuf is of the form
- *         "-"? ("0x" | "0X")? digit+
- *     "0x"/"0X" are present only for x and X conversions, with F_ALT
- *         set in flags.  The case of hex digits will be correct,
- *     There will be at least prec digits, zero-filled on the left if
- *         necessary to get that many.
- * val          object to be converted
- * flags        bitmask of format flags; only F_ALT is looked at
- * prec         minimum number of digits; 0-fill on left if needed
- * type         a character in [duoxX]; u acts the same as d
- *
- * CAUTION:  o, x and X conversions on regular ints can never
- * produce a '-' sign, but can for Python's unbounded ints.
- */
-PyObject*
-_PyBytes_FormatLong(PyObject *val, int flags, int prec, int type,
-                     char **pbuf, int *plen)
-{
-    PyObject *result = NULL;
-    char *buf;
-    Py_ssize_t i;
-    int sign;           /* 1 if '-', else 0 */
-    int len;            /* number of characters */
-    Py_ssize_t llen;
-    int numdigits;      /* len == numnondigits + numdigits */
-    int numnondigits = 0;
-
-    /* Avoid exceeding SSIZE_T_MAX */
-    if (prec > INT_MAX-3) {
-        PyErr_SetString(PyExc_OverflowError,
-                        "precision too large");
-        return NULL;
-    }
-
-    switch (type) {
-    case 'd':
-    case 'u':
-        /* Special-case boolean: we want 0/1 */
-        if (PyBool_Check(val))
-            result = PyNumber_ToBase(val, 10);
-        else
-            result = Py_TYPE(val)->tp_str(val);
-        break;
-    case 'o':
-        numnondigits = 2;
-        result = PyNumber_ToBase(val, 8);
-        break;
-    case 'x':
-    case 'X':
-        numnondigits = 2;
-        result = PyNumber_ToBase(val, 16);
-        break;
-    default:
-        assert(!"'type' not in [duoxX]");
-    }
-    if (!result)
-        return NULL;
-
-    buf = _PyUnicode_AsString(result);
-    if (!buf) {
-        Py_DECREF(result);
-        return NULL;
-    }
-
-    /* To modify the string in-place, there can only be one reference. */
-    if (Py_REFCNT(result) != 1) {
-        PyErr_BadInternalCall();
-        return NULL;
-    }
-    llen = PyUnicode_GetLength(result);
-    if (llen > INT_MAX) {
-        PyErr_SetString(PyExc_ValueError,
-                        "string too large in _PyBytes_FormatLong");
-        return NULL;
-    }
-    len = (int)llen;
-    if (buf[len-1] == 'L') {
-        --len;
-        buf[len] = '\0';
-    }
-    sign = buf[0] == '-';
-    numnondigits += sign;
-    numdigits = len - numnondigits;
-    assert(numdigits > 0);
-
-    /* Get rid of base marker unless F_ALT */
-    if (((flags & F_ALT) == 0 &&
-        (type == 'o' || type == 'x' || type == 'X'))) {
-        assert(buf[sign] == '0');
-        assert(buf[sign+1] == 'x' || buf[sign+1] == 'X' ||
-               buf[sign+1] == 'o');
-        numnondigits -= 2;
-        buf += 2;
-        len -= 2;
-        if (sign)
-            buf[0] = '-';
-        assert(len == numnondigits + numdigits);
-        assert(numdigits > 0);
-    }
-
-    /* Fill with leading zeroes to meet minimum width. */
-    if (prec > numdigits) {
-        PyObject *r1 = PyBytes_FromStringAndSize(NULL,
-                                numnondigits + prec);
-        char *b1;
-        if (!r1) {
-            Py_DECREF(result);
-            return NULL;
-        }
-        b1 = PyBytes_AS_STRING(r1);
-        for (i = 0; i < numnondigits; ++i)
-            *b1++ = *buf++;
-        for (i = 0; i < prec - numdigits; i++)
-            *b1++ = '0';
-        for (i = 0; i < numdigits; i++)
-            *b1++ = *buf++;
-        *b1 = '\0';
-        Py_DECREF(result);
-        result = r1;
-        buf = PyBytes_AS_STRING(result);
-        len = numnondigits + prec;
-    }
-
-    /* Fix up case for hex conversions. */
-    if (type == 'X') {
-        /* Need to convert all lower case letters to upper case.
-           and need to convert 0x to 0X (and -0x to -0X). */
-        for (i = 0; i < len; i++)
-            if (buf[i] >= 'a' && buf[i] <= 'x')
-                buf[i] -= 'a'-'A';
-    }
-    *pbuf = buf;
-    *plen = len;
-    return result;
-}
-
 void
 PyBytes_Fini(void)
 {
index 3afb799fc3bfb5e1c50e502fa3d257c38328fa7b..ac77114da97bc0a73e28f189bee43ace395d724a 100644 (file)
@@ -13438,19 +13438,140 @@ formatfloat(PyObject *v, int flags, int prec, int type)
     return result;
 }
 
+/* formatlong() emulates the format codes d, u, o, x and X, and
+ * the F_ALT flag, for Python's long (unbounded) ints.  It's not used for
+ * Python's regular ints.
+ * Return value:  a new PyUnicodeObject*, or NULL if error.
+ *     The output string is of the form
+ *         "-"? ("0x" | "0X")? digit+
+ *     "0x"/"0X" are present only for x and X conversions, with F_ALT
+ *         set in flags.  The case of hex digits will be correct,
+ *     There will be at least prec digits, zero-filled on the left if
+ *         necessary to get that many.
+ * val          object to be converted
+ * flags        bitmask of format flags; only F_ALT is looked at
+ * prec         minimum number of digits; 0-fill on left if needed
+ * type         a character in [duoxX]; u acts the same as d
+ *
+ * CAUTION:  o, x and X conversions on regular ints can never
+ * produce a '-' sign, but can for Python's unbounded ints.
+ */
 static PyObject*
 formatlong(PyObject *val, int flags, int prec, int type)
 {
+    PyObject *result = NULL;
     char *buf;
-    int len;
-    PyObject *str; /* temporary string object. */
-    PyObject *result;
+    Py_ssize_t i;
+    int sign;           /* 1 if '-', else 0 */
+    int len;            /* number of characters */
+    Py_ssize_t llen;
+    int numdigits;      /* len == numnondigits + numdigits */
+    int numnondigits = 0;
+
+    /* Avoid exceeding SSIZE_T_MAX */
+    if (prec > INT_MAX-3) {
+        PyErr_SetString(PyExc_OverflowError,
+                        "precision too large");
+        return NULL;
+    }
 
-    str = _PyBytes_FormatLong(val, flags, prec, type, &buf, &len);
-    if (!str)
+    assert(PyLong_Check(val));
+
+    switch (type) {
+    case 'd':
+    case 'u':
+        /* Special-case boolean: we want 0/1 */
+        result = Py_TYPE(val)->tp_str(val);
+        break;
+    case 'o':
+        numnondigits = 2;
+        result = PyNumber_ToBase(val, 8);
+        break;
+    case 'x':
+    case 'X':
+        numnondigits = 2;
+        result = PyNumber_ToBase(val, 16);
+        break;
+    default:
+        assert(!"'type' not in [duoxX]");
+    }
+    if (!result)
         return NULL;
-    result = PyUnicode_DecodeASCII(buf, len, NULL);
-    Py_DECREF(str);
+
+    assert(unicode_modifiable(result));
+    assert(PyUnicode_IS_READY(result));
+    assert(PyUnicode_IS_ASCII(result));
+
+    /* To modify the string in-place, there can only be one reference. */
+    if (Py_REFCNT(result) != 1) {
+        PyErr_BadInternalCall();
+        return NULL;
+    }
+    buf = PyUnicode_DATA(result);
+    llen = PyUnicode_GET_LENGTH(result);
+    if (llen > INT_MAX) {
+        PyErr_SetString(PyExc_ValueError,
+                        "string too large in _PyBytes_FormatLong");
+        return NULL;
+    }
+    len = (int)llen;
+    sign = buf[0] == '-';
+    numnondigits += sign;
+    numdigits = len - numnondigits;
+    assert(numdigits > 0);
+
+    /* Get rid of base marker unless F_ALT */
+    if (((flags & F_ALT) == 0 &&
+        (type == 'o' || type == 'x' || type == 'X'))) {
+        assert(buf[sign] == '0');
+        assert(buf[sign+1] == 'x' || buf[sign+1] == 'X' ||
+               buf[sign+1] == 'o');
+        numnondigits -= 2;
+        buf += 2;
+        len -= 2;
+        if (sign)
+            buf[0] = '-';
+        assert(len == numnondigits + numdigits);
+        assert(numdigits > 0);
+    }
+
+    /* Fill with leading zeroes to meet minimum width. */
+    if (prec > numdigits) {
+        PyObject *r1 = PyBytes_FromStringAndSize(NULL,
+                                numnondigits + prec);
+        char *b1;
+        if (!r1) {
+            Py_DECREF(result);
+            return NULL;
+        }
+        b1 = PyBytes_AS_STRING(r1);
+        for (i = 0; i < numnondigits; ++i)
+            *b1++ = *buf++;
+        for (i = 0; i < prec - numdigits; i++)
+            *b1++ = '0';
+        for (i = 0; i < numdigits; i++)
+            *b1++ = *buf++;
+        *b1 = '\0';
+        Py_DECREF(result);
+        result = r1;
+        buf = PyBytes_AS_STRING(result);
+        len = numnondigits + prec;
+    }
+
+    /* Fix up case for hex conversions. */
+    if (type == 'X') {
+        /* Need to convert all lower case letters to upper case.
+           and need to convert 0x to 0X (and -0x to -0X). */
+        for (i = 0; i < len; i++)
+            if (buf[i] >= 'a' && buf[i] <= 'x')
+                buf[i] -= 'a'-'A';
+    }
+    if (!PyUnicode_Check(result) || len != PyUnicode_GET_LENGTH(result)) {
+        PyObject *unicode;
+        unicode = unicode_fromascii((unsigned char *)buf, len);
+        Py_DECREF(result);
+        result = unicode;
+    }
     return result;
 }