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.
This commit is contained in:
Eric Smith 2008-02-10 01:36:53 +00:00
parent 14a1b8cc46
commit 5e527ebee1
5 changed files with 126 additions and 33 deletions

View 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

View 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

View 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

View 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."},

View 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 *