]> granicus.if.org Git - python/commitdiff
Added PyNumber_ToBase and supporting routines _PyInt_Format and
authorEric Smith <eric@trueblade.com>
Sun, 10 Feb 2008 01:36:53 +0000 (01:36 +0000)
committerEric Smith <eric@trueblade.com>
Sun, 10 Feb 2008 01:36:53 +0000 (01:36 +0000)
_PyLong_Format.  In longobject.c, changed long_format to
_PyLong_Format.  In intobject.c, changed uses of PyOS_snprintf to
_PyInt_Format instead.

_PyLong_Format is similar to py3k's routine of the same name, except
it has 2 additional parameters: addL and newstyle.  addL was existing
in long_format, and controls adding the trailing "L".  This is
unneeded in py3k.  newstyle is used to control whether octal prepends
"0" (the pre-2.6 style), or "0o" (the 3.0 sytle).

PyNumber_ToBase is needed for PEP 3127 (Integer Literal Support and
Syntax) and PEP 3101 (Advanced String Formatting).

This changeset does not need merging into py3k.

Include/intobject.h
Include/longobject.h
Objects/abstract.c
Objects/intobject.c
Objects/longobject.c

index 7b5052553e8e95002ce2a7d5316f5692d65b3ec2..66a62d9553506b577a857654b1d03f5aae369f6f 100644 (file)
@@ -62,6 +62,12 @@ PyAPI_FUNC(long) PyOS_strtol(char *, char **, int);
 /* free list api */
 PyAPI_FUNC(void) PyInt_CompactFreeList(size_t *, size_t *, size_t *);
 
+/* 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
+   a leading "0" */
+PyAPI_FUNC(PyObject*) _PyInt_Format(PyIntObject* v, int base, int newstyle);
+
 #ifdef __cplusplus
 }
 #endif
index 379e93492d64b8e6deb95c133133489edb8ab339..8a9e6763b1b0a53f092b1ab312956bc39393f815 100644 (file)
@@ -112,6 +112,13 @@ PyAPI_FUNC(int) _PyLong_AsByteArray(PyLongObject* v,
        unsigned char* bytes, size_t n,
        int little_endian, int is_signed);
 
+/* _PyLong_Format: Convert the long to a string object with given base,
+   appending a base prefix of 0[box] if base is 2, 8 or 16.
+   Add a trailing "L" if addL is non-zero.
+   If newstyle is zero, then use the pre-2.6 behavior of octal having
+   a leading "0", instead of the prefix "0o" */
+PyAPI_FUNC(PyObject *) _PyLong_Format(PyObject *aa, int base, int addL, int newstyle);
+
 #ifdef __cplusplus
 }
 #endif
index a3e159a105e016bf15c11473c0c33b1237629432..89a78c6da6af0260a2104008bbacee58480fa43d 100644 (file)
@@ -1262,6 +1262,25 @@ PyNumber_Float(PyObject *o)
        return PyFloat_FromString(o, NULL);
 }
 
+PyObject *
+PyNumber_ToBase(PyObject *n, int base)
+{
+       PyObject *res = NULL;
+       PyObject *index = PyNumber_Index(n);
+
+       if (!index)
+               return NULL;
+       if (PyLong_Check(index))
+               res = _PyLong_Format(index, base, 0, 1);
+       else if (PyInt_Check(index))
+               res = _PyInt_Format((PyIntObject*)index, base, 1);
+       else
+               assert("PyNumber_ToBase: not long or int");
+       Py_DECREF(index);
+       return res;
+}
+
+
 /* Operations on sequences */
 
 int
index 7c2a6fba5f35b1fe4ac3e6037f19e06f8f4b38cc..2fdea259e28a78db2ea618b394f33cac3041e4a9 100644 (file)
@@ -437,9 +437,7 @@ int_print(PyIntObject *v, FILE *fp, int flags)
 static PyObject *
 int_repr(PyIntObject *v)
 {
-       char buf[64];
-       PyOS_snprintf(buf, sizeof(buf), "%ld", v->ob_ival);
-       return PyString_FromString(buf);
+       return _PyInt_Format(v, 10, 0);
 }
 
 static int
@@ -938,27 +936,13 @@ int_float(PyIntObject *v)
 static PyObject *
 int_oct(PyIntObject *v)
 {
-       char buf[100];
-       long x = v -> ob_ival;
-       if (x < 0)
-               PyOS_snprintf(buf, sizeof(buf), "-0%lo", -x);
-       else if (x == 0)
-               strcpy(buf, "0");
-       else
-               PyOS_snprintf(buf, sizeof(buf), "0%lo", x);
-       return PyString_FromString(buf);
+       return _PyInt_Format(v, 8, 0);
 }
 
 static PyObject *
 int_hex(PyIntObject *v)
 {
-       char buf[100];
-       long x = v -> ob_ival;
-       if (x < 0)
-               PyOS_snprintf(buf, sizeof(buf), "-0x%lx", -x);
-       else
-               PyOS_snprintf(buf, sizeof(buf), "0x%lx", x);
-       return PyString_FromString(buf);
+       return _PyInt_Format(v, 16, 0);
 }
 
 static PyObject *
@@ -1056,6 +1040,74 @@ int_getN(PyIntObject *v, void *context) {
        return PyInt_FromLong((intptr_t)context);
 }
 
+/* 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
+   a leading "0" */
+PyAPI_FUNC(PyObject*)
+_PyInt_Format(PyIntObject *v, int base, int newstyle)
+{
+       /* There are no doubt many, many ways to optimize this, using code
+          similar to _PyLong_Format */
+       long n = v->ob_ival;
+       int  negative = n < 0;
+       int is_zero = n == 0;
+
+       /* For the reasoning behind this size, see
+          http://c-faq.com/misc/hexio.html. Then, add a few bytes for
+          the possible sign and prefix "0[box]" */
+       char buf[sizeof(n)*CHAR_BIT+6];
+
+       /* Start by pointing to the end of the buffer.  We fill in from
+          the back forward. */
+       char* p = &buf[sizeof(buf)];
+
+       assert(base >= 2 && base <= 36);
+
+       do {
+               /* I'd use i_divmod, except it doesn't produce the results
+                  I want when n is negative.  So just duplicate the salient
+                  part here. */
+               long div = n / base;
+               long mod = n - div * base;
+
+               /* convert abs(mod) to the right character in [0-9, a-z] */
+               char cdigit = (char)(mod < 0 ? -mod : mod);
+               cdigit += (cdigit < 10) ? '0' : 'a'-10;
+               *--p = cdigit;
+
+               n = div;
+       } while(n);
+
+       if (base == 2) {
+               *--p = 'b';
+               *--p = '0';
+       }
+       else if (base == 8) {
+               if (newstyle) {
+                       *--p = 'o';
+                       *--p = '0';
+               }
+               else
+                       if (!is_zero)
+                               *--p = '0';
+       }
+       else if (base == 16) {
+               *--p = 'x';
+               *--p = '0';
+       }
+       else if (base != 10) {
+               *--p = '#';
+               *--p = '0' + base%10;
+               if (base > 10)
+                       *--p = '0' + base/10;
+       }
+       if (negative)
+               *--p = '-';
+
+       return PyString_FromStringAndSize(p, &buf[sizeof(buf)] - p);
+}
+
 static PyMethodDef int_methods[] = {
        {"conjugate",   (PyCFunction)int_int,   METH_NOARGS,
         "Returns self, the complex conjugate of any int."},
index 9fb583281abd3dcf47f635a82e2160acd2530c9f..3ee2992bfca61f5f4f616d695741b53514c927fa 100644 (file)
@@ -35,7 +35,6 @@ static PyLongObject *long_normalize(PyLongObject *);
 static PyLongObject *mul1(PyLongObject *, wdigit);
 static PyLongObject *muladd1(PyLongObject *, wdigit, wdigit);
 static PyLongObject *divrem1(PyLongObject *, digit, digit *);
-static PyObject *long_format(PyObject *aa, int base, int addL);
 
 #define SIGCHECK(PyTryBlock) \
        if (--_Py_Ticker < 0) { \
@@ -1140,7 +1139,7 @@ muladd1(PyLongObject *a, wdigit n, wdigit extra)
 /* Divide long pin, w/ size digits, by non-zero digit n, storing quotient
    in pout, and returning the remainder.  pin and pout point at the LSD.
    It's OK for pin == pout on entry, which saves oodles of mallocs/frees in
-   long_format, but that should be done with great care since longs are
+   _PyLong_Format, but that should be done with great care since longs are
    immutable. */
 
 static digit
@@ -1178,12 +1177,13 @@ divrem1(PyLongObject *a, digit n, digit *prem)
        return long_normalize(z);
 }
 
-/* Convert a long int object to a string, using a given conversion base.
-   Return a string object.
-   If base is 8 or 16, add the proper prefix '0' or '0x'. */
-
-static PyObject *
-long_format(PyObject *aa, int base, int addL)
+/* Convert the long to a string object with given base,
+   appending a base prefix of 0[box] if base is 2, 8 or 16.
+   Add a trailing "L" if addL is non-zero.
+   If newstyle is zero, then use the pre-2.6 behavior of octal having
+   a leading "0", instead of the prefix "0o" */
+PyAPI_FUNC(PyObject *)
+_PyLong_Format(PyObject *aa, int base, int addL, int newstyle)
 {
        register PyLongObject *a = (PyLongObject *)aa;
        PyStringObject *str;
@@ -1309,9 +1309,18 @@ long_format(PyObject *aa, int base, int addL)
                Py_DECREF(scratch);
        }
 
-       if (base == 8) {
-               if (size_a != 0)
+       if (base == 2) {
+               *--p = 'b';
+               *--p = '0';
+       }
+       else if (base == 8) {
+               if (newstyle) {
+                       *--p = 'o';
                        *--p = '0';
+               }
+               else
+                       if (size_a != 0)
+                               *--p = '0';
        }
        else if (base == 16) {
                *--p = 'x';
@@ -1888,13 +1897,13 @@ long_dealloc(PyObject *v)
 static PyObject *
 long_repr(PyObject *v)
 {
-       return long_format(v, 10, 1);
+       return _PyLong_Format(v, 10, 1, 0);
 }
 
 static PyObject *
 long_str(PyObject *v)
 {
-       return long_format(v, 10, 0);
+       return _PyLong_Format(v, 10, 0, 0);
 }
 
 static int
@@ -3268,13 +3277,13 @@ long_float(PyObject *v)
 static PyObject *
 long_oct(PyObject *v)
 {
-       return long_format(v, 8, 1);
+       return _PyLong_Format(v, 8, 1, 0);
 }
 
 static PyObject *
 long_hex(PyObject *v)
 {
-       return long_format(v, 16, 1);
+       return _PyLong_Format(v, 16, 1, 0);
 }
 
 static PyObject *