diff -r 74b7ff20e0e4 Doc/c-api/long.rst --- a/Doc/c-api/long.rst Tue Jul 02 00:17:14 2013 +0200 +++ b/Doc/c-api/long.rst Tue Jul 02 01:49:04 2013 +0200 @@ -74,6 +74,22 @@ All integers are implemented as "long" i or *NULL* on failure. +.. c:function:: PyObject* PyLong_FromIntMax_t(intmax_t v) + + Return a new :c:type:`PyLongObject` object from a C :c:type:`intmax_t`, + or *NULL* on failure. + + .. versionadded:: 3.4 + + +.. c:function:: PyObject* PyLong_FromUintMax_t(uintmax_t v) + + Return a new :c:type:`PyLongObject` object from a C :c:type:`uintmax_t`, + or *NULL* on failure. + + .. versionadded:: 3.4 + + .. c:function:: PyObject* PyLong_FromDouble(double v) Return a new :c:type:`PyLongObject` object from the integer part of *v*, or @@ -188,6 +204,17 @@ All integers are implemented as "long" i :c:type:`Py_ssize_t`. +.. c:function:: intmax_t PyLong_AsIntMax_t(PyObject *pylong) + + Return a C :c:type:`intmax_t` representation of *pylong*. *pylong* must + be an instance of :c:type:`PyLongObject`. + + Return ``-1`` and raise :exc:`OverflowError` if the value of *pylong* is out + of range for a :c:type:`intmax_t`. + + .. versionadded:: 3.4 + + .. c:function:: unsigned long PyLong_AsUnsignedLong(PyObject *pylong) .. index:: @@ -245,6 +272,17 @@ All integers are implemented as "long" i return the reduction of that value modulo :const:`PY_ULLONG_MAX + 1`. +.. c:function:: uintmax_t PyLong_AsUintMax_t(PyObject *pylong) + + Return a C :c:type:`uintmax_t` representation of *pylong*. + *pylong* must be an instance of :c:type:`PyLongObject`. + + Return ``-1`` and raise :exc:`OverflowError` if the value of *pylong* is out + of range for an :c:type:`uintmax_t`. + + .. versionadded:: 3.4 + + .. c:function:: double PyLong_AsDouble(PyObject *pylong) Return a C :c:type:`double` representation of *pylong*. *pylong* must be diff -r 74b7ff20e0e4 Include/longobject.h --- a/Include/longobject.h Tue Jul 02 00:17:14 2013 +0200 +++ b/Include/longobject.h Tue Jul 02 01:49:04 2013 +0200 @@ -84,6 +82,11 @@ PyAPI_FUNC(double) PyLong_AsDouble(PyObj PyAPI_FUNC(PyObject *) PyLong_FromVoidPtr(void *); PyAPI_FUNC(void *) PyLong_AsVoidPtr(PyObject *); +PyAPI_FUNC(PyObject *) PyLong_FromIntMax_t(intmax_t); +PyAPI_FUNC(PyObject *) PyLong_FromUintMax_t(uintmax_t); +PyAPI_FUNC(intmax_t) PyLong_AsIntMax_t(PyObject *); +PyAPI_FUNC(uintmax_t) PyLong_AsUintMax_t(PyObject *); + #ifdef HAVE_LONG_LONG PyAPI_FUNC(PyObject *) PyLong_FromLongLong(PY_LONG_LONG); PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG); diff -r 74b7ff20e0e4 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Tue Jul 02 00:17:14 2013 +0200 +++ b/Modules/_testcapimodule.c Tue Jul 02 01:49:04 2013 +0200 @@ -57,6 +57,8 @@ test_config(PyObject *self) #ifdef HAVE_LONG_LONG CHECK_SIZEOF(SIZEOF_LONG_LONG, PY_LONG_LONG); #endif + CHECK_SIZEOF(SIZEOF_INTMAX_T, intmax_t); + CHECK_SIZEOF(SIZEOF_UINTMAX_T, uintmax_t); #undef CHECK_SIZEOF @@ -2511,6 +2513,110 @@ test_decref_doesnt_leak(PyObject *ob) Py_RETURN_NONE; } +static PyObject * +test_intmax(PyObject *self) +{ + intmax_t sint; + uintmax_t uint; + PyObject *obj = NULL, *one = NULL, *overflow = NULL; + PyObject *res = NULL; + + /* test PyLong_FromIntMax_t() and PyLong_AsIntMax_t() with INTMAX_MAX */ + obj = PyLong_FromIntMax_t(INTMAX_MAX); + if (obj == NULL) + goto error; + sint = PyLong_AsIntMax_t(obj); + if (sint != INTMAX_MAX) { + PyErr_SetString(PyExc_RuntimeError, + "PyLong_AsIntMax_t(INTMAX_MAX) failed"); + goto error; + } + + /* test PyLong_AsIntMax_t(INTMAX_MAX+1) overflow */ + one = PyLong_FromLong(1); + if (one == NULL) + goto error; + overflow = PyNumber_Add(obj, one); + if (overflow == NULL) + goto error; + sint = PyLong_AsIntMax_t(overflow); + if (sint != -1 + || !PyErr_ExceptionMatches(PyExc_OverflowError)) + { + PyErr_SetString(PyExc_RuntimeError, + "PyLong_AsIntMax_t(INTMAX_MAX+1) didn't overflow"); + goto error; + } + PyErr_Clear(); + Py_CLEAR(obj); + Py_CLEAR(overflow); + + /* test PyLong_FromIntMax_t() and PyLong_AsIntMax_t() with INTMAX_MIN */ + obj = PyLong_FromIntMax_t(INTMAX_MIN); + if (obj == NULL) + goto error; + sint = PyLong_AsIntMax_t(obj); + if (sint != INTMAX_MIN) { + PyErr_SetString(PyExc_RuntimeError, + "PyLong_AsIntMax_t(INTMAX_MIN) failed"); + goto error; + } + + /* test PyLong_AsIntMax_t(INTMAX_MIN-1) underflow */ + one = PyLong_FromLong(1); + if (one == NULL) + goto error; + overflow = PyNumber_Subtract(obj, one); + if (overflow == NULL) + goto error; + sint = PyLong_AsIntMax_t(overflow); + if (sint != -1 + || !PyErr_ExceptionMatches(PyExc_OverflowError)) + { + PyErr_SetString(PyExc_RuntimeError, + "PyLong_AsIntMax_t(INTMAX_MIN-1) didn't overflow"); + goto error; + } + PyErr_Clear(); + Py_CLEAR(obj); + Py_CLEAR(overflow); + + /* test PyLong_FromUintMax_t() and PyLong_AsUintMax_t() with UINTMAX_MAX */ + obj = PyLong_FromUintMax_t(UINTMAX_MAX); + if (obj == NULL) + goto error; + uint = PyLong_AsUintMax_t(obj); + if (uint != UINTMAX_MAX) { + PyErr_SetString(PyExc_RuntimeError, + "PyLong_AsUintMax_t(UINTMAX_MAX) failed"); + goto error; + } + + /* test PyLong_AsUintMax_t(UINTMAX_MAX+1) overflow */ + overflow = PyNumber_Add(obj, one); + if (overflow == NULL) + goto error; + uint = PyLong_AsUintMax_t(overflow); + if (uint != (uintmax_t)-1 + || !PyErr_ExceptionMatches(PyExc_OverflowError)) + { + PyErr_SetString(PyExc_RuntimeError, + "PyLong_AsIntMax_t(UINTMAX_MAX+1) didn't overflow"); + goto error; + } + PyErr_Clear(); + Py_CLEAR(overflow); + + Py_INCREF(Py_None); + res = Py_None; + +error: + Py_XDECREF(obj); + Py_XDECREF(one); + Py_XDECREF(overflow); + return res; +} + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS}, @@ -2611,6 +2717,7 @@ static PyMethodDef TestMethods[] = { {"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS}, {"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS}, {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, + {"test_intmax", (PyCFunction)test_intmax, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff -r 74b7ff20e0e4 Objects/longobject.c --- a/Objects/longobject.c Tue Jul 02 00:17:14 2013 +0200 +++ b/Objects/longobject.c Tue Jul 02 01:49:04 2013 +0200 @@ -314,6 +314,7 @@ PyLong_FromDouble(double dval) */ #define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN) #define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN) +#define PY_ABS_INTMAX_MIN (0-(unsigned long)INTMAX_MIN) /* Get a C long int from a long int object or any object that has an __int__ method. @@ -1078,6 +1079,186 @@ PyLong_FromUnsignedLongLong(unsigned PY_ return (PyObject *)v; } +PyObject * +PyLong_FromIntMax_t(intmax_t ival) +{ + PyLongObject *v; + uintmax_t abs_ival; + uintmax_t t; /* unsigned so >> doesn't propagate sign bit */ + int ndigits = 0; + int negative = 0; + + CHECK_SMALL_INT(ival); + if (ival < 0) { + /* avoid signed overflow on negation; see comments + in PyLong_FromLong above. */ + abs_ival = (uintmax_t)(-1-ival) + 1; + negative = 1; + } + else { + abs_ival = (uintmax_t)ival; + } + + /* Count the number of Python digits. + We used to pick 5 ("big enough for anything"), but that's a + waste of time and space given that 5*15 = 75 bits are rarely + needed. */ + t = abs_ival; + while (t) { + ++ndigits; + t >>= PyLong_SHIFT; + } + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + Py_SIZE(v) = negative ? -ndigits : ndigits; + t = abs_ival; + while (t) { + *p++ = (digit)(t & PyLong_MASK); + t >>= PyLong_SHIFT; + } + } + return (PyObject *)v; +} + + +PyObject * +PyLong_FromUintMax_t(uintmax_t ival) +{ + PyLongObject *v; + uintmax_t t; + int ndigits = 0; + + if (ival < (uintmax_t)PyLong_BASE) + return PyLong_FromLong((long)ival); + + /* Count the number of Python digits. */ + t = ival; + while (t) { + ++ndigits; + t >>= PyLong_SHIFT; + } + + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + Py_SIZE(v) = ndigits; + while (ival) { + *p++ = (digit)(ival & PyLong_MASK); + ival >>= PyLong_SHIFT; + } + } + return (PyObject *)v; +} + +intmax_t +PyLong_AsIntMax_t(PyObject *vv) +{ + PyLongObject *v; + uintmax_t x, prev; + intmax_t res; + Py_ssize_t i; + int sign; + + if (vv == NULL) { + PyErr_BadInternalCall(); + return -1; + } + + if (!PyLong_Check(vv)) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + + res = -1; + v = (PyLongObject *)vv; + i = Py_SIZE(v); + + switch (i) { + case -1: + res = -(sdigit)v->ob_digit[0]; + break; + case 0: + res = 0; + break; + case 1: + res = v->ob_digit[0]; + break; + default: + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -(i); + } + while (--i >= 0) { + prev = x; + x = (x << PyLong_SHIFT) | v->ob_digit[i]; + if ((x >> PyLong_SHIFT) != prev) + goto overflow; + } + /* Haven't lost any bits, but casting to intmax_t requires extra + * care (see comment above). + */ + if (x <= (uintmax_t)INTMAX_MAX) { + res = (intmax_t)x * sign; + } + else if (sign < 0 && x == PY_ABS_INTMAX_MIN) { + res = INTMAX_MIN; + } + else { + goto overflow; + } + } + return res; + + overflow: + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C intmax_t"); + return -1; +} + +uintmax_t +PyLong_AsUintMax_t(PyObject *vv) +{ + PyLongObject *v; + uintmax_t x, prev; + Py_ssize_t i; + + if (vv == NULL) { + PyErr_BadInternalCall(); + return (uintmax_t)-1; + } + if (!PyLong_Check(vv)) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return (uintmax_t)-1; + } + + v = (PyLongObject *)vv; + i = Py_SIZE(v); + x = 0; + if (i < 0) { + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to unsigned int"); + return (uintmax_t)-1; + } + switch (i) { + case 0: return 0; + case 1: return v->ob_digit[0]; + } + while (--i >= 0) { + prev = x; + x = (x << PyLong_SHIFT) | v->ob_digit[i]; + if ((x >> PyLong_SHIFT) != prev) { + PyErr_SetString(PyExc_OverflowError, + "python int too large to convert to C uintmax_t"); + return (uintmax_t)-1; + } + } + return x; +} + + /* Create a new long int object from a C Py_ssize_t. */ PyObject * diff -r 74b7ff20e0e4 PC/pyconfig.h --- a/PC/pyconfig.h Tue Jul 02 00:17:14 2013 +0200 +++ b/PC/pyconfig.h Tue Jul 02 01:49:04 2013 +0200 @@ -202,6 +202,23 @@ typedef _W64 int ssize_t; #endif #endif /* MS_WIN32 && !MS_WIN64 */ + + +#if !defined(_MSC_VER) || _MSC_VER >= 1600 +# include +#else +/* Visual Studio 2008 and older does not provide stdint.h */ +typedef __int64 intmax_t; +typedef unsigned __int64 uintmax_t; +#endif + +#if UINTMAX_MAX == 0xffffffffffffffffU +# define SIZEOF_INTMAX_T 8 +# define SIZEOF_UINTMAX_T 8 +#else +# error "unsupported configuration: sizeof(uintptr_t) != 8" +#endif + typedef int pid_t; #include diff -r 74b7ff20e0e4 configure.ac --- a/configure.ac Tue Jul 02 00:17:14 2013 +0200 +++ b/configure.ac Tue Jul 02 01:49:04 2013 +0200 @@ -1645,6 +1645,8 @@ cat >> confdefs.h <<\EOF EOF # Type availability checks +AC_TYPE_INTMAX_T +AC_TYPE_UINTMAX_T AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_PID_T @@ -1691,6 +1693,8 @@ AC_CHECK_SIZEOF(double, 8) AC_CHECK_SIZEOF(fpos_t, 4) AC_CHECK_SIZEOF(size_t, 4) AC_CHECK_SIZEOF(pid_t, 4) +AC_CHECK_SIZEOF(intmax_t) +AC_CHECK_SIZEOF(uintmax_t) AC_MSG_CHECKING(for long long support) have_long_long=no diff -r 74b7ff20e0e4 pyconfig.h.in --- a/pyconfig.h.in Tue Jul 02 00:17:14 2013 +0200 +++ b/pyconfig.h.in Tue Jul 02 01:49:04 2013 +0200 @@ -432,6 +432,9 @@ /* Define if your compiler provides int64_t. */ #undef HAVE_INT64_T +/* Define to 1 if the system has the type `intmax_t'. */ +#undef HAVE_INTMAX_T + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H @@ -531,6 +534,9 @@ /* Define this if you have the type long long. */ #undef HAVE_LONG_LONG +/* Define to 1 if the system has the type `long long int'. */ +#undef HAVE_LONG_LONG_INT + /* Define to 1 if you have the `lstat' function. */ #undef HAVE_LSTAT @@ -1062,6 +1068,9 @@ /* Define if your compiler provides uint64_t. */ #undef HAVE_UINT64_T +/* Define to 1 if the system has the type `uintmax_t'. */ +#undef HAVE_UINTMAX_T + /* Define to 1 if the system has the type `uintptr_t'. */ #undef HAVE_UINTPTR_T @@ -1077,6 +1086,9 @@ /* Define to 1 if you have the `unsetenv' function. */ #undef HAVE_UNSETENV +/* Define to 1 if the system has the type `unsigned long long int'. */ +#undef HAVE_UNSIGNED_LONG_LONG_INT + /* Define if you have a useable wchar_t type defined in wchar.h; useable means wchar_t must be an unsigned type with at least 16 bits. (see Include/unicodeobject.h). */ @@ -1208,6 +1220,9 @@ /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT +/* The size of `intmax_t', as computed by sizeof. */ +#undef SIZEOF_INTMAX_T + /* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG @@ -1235,6 +1250,9 @@ /* The size of `time_t', as computed by sizeof. */ #undef SIZEOF_TIME_T +/* The size of `uintmax_t', as computed by sizeof. */ +#undef SIZEOF_UINTMAX_T + /* The size of `uintptr_t', as computed by sizeof. */ #undef SIZEOF_UINTPTR_T @@ -1435,6 +1453,10 @@ such a type exists and the standard includes do not define it. */ #undef int64_t +/* Define to the widest signed integer type if and do + not define. */ +#undef intmax_t + /* Define to `int' if does not define. */ #undef mode_t @@ -1464,6 +1486,10 @@ such a type exists and the standard includes do not define it. */ #undef uint64_t +/* Define to the widest unsigned integer type if and + do not define. */ +#undef uintmax_t + /* Define to empty if the keyword does not work. */ #undef volatile