diff options
author | Eric Smith <eric@trueblade.com> | 2008-02-10 01:36:53 (GMT) |
---|---|---|
committer | Eric Smith <eric@trueblade.com> | 2008-02-10 01:36:53 (GMT) |
commit | 5e527ebee1580f052fc53aacabe3906ffcdd4805 (patch) | |
tree | b77c8ca7e6fcd8a2cd31c184c764a79633e2fb85 /Objects | |
parent | 14a1b8cc469375577ea42152bfe559fa52d6ece7 (diff) | |
download | cpython-5e527ebee1580f052fc53aacabe3906ffcdd4805.zip cpython-5e527ebee1580f052fc53aacabe3906ffcdd4805.tar.gz cpython-5e527ebee1580f052fc53aacabe3906ffcdd4805.tar.bz2 |
Added PyNumber_ToBase and supporting routines _PyInt_Format and
_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.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/abstract.c | 19 | ||||
-rw-r--r-- | Objects/intobject.c | 90 | ||||
-rw-r--r-- | Objects/longobject.c | 37 |
3 files changed, 113 insertions, 33 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index a3e159a..89a78c6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -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 diff --git a/Objects/intobject.c b/Objects/intobject.c index 7c2a6fb..2fdea25 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -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."}, diff --git a/Objects/longobject.c b/Objects/longobject.c index 9fb5832..3ee2992 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -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 * |