Index: configure =================================================================== --- configure (revision 67111) +++ configure (working copy) @@ -6957,6 +6957,386 @@ fi + + { echo "$as_me:$LINENO: checking for int32_t" >&5 +echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; } +if test "${ac_cv_c_int32_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_int32_t=no + for ac_type in 'int32_t' 'int' 'long int' \ + 'long long int' 'short int' 'signed char'; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 1))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 1) + < ($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 2))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + case $ac_type in + int32_t) ac_cv_c_int32_t=yes ;; + *) ac_cv_c_int32_t=$ac_type ;; +esac + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_int32_t" != no && break + done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_int32_t" >&5 +echo "${ECHO_T}$ac_cv_c_int32_t" >&6; } + case $ac_cv_c_int32_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int32_t $ac_cv_c_int32_t +_ACEOF +;; + esac + + + { echo "$as_me:$LINENO: checking for int64_t" >&5 +echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; } +if test "${ac_cv_c_int64_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_int64_t=no + for ac_type in 'int64_t' 'int' 'long int' \ + 'long long int' 'short int' 'signed char'; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 1))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 1) + < ($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 2))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + case $ac_type in + int64_t) ac_cv_c_int64_t=yes ;; + *) ac_cv_c_int64_t=$ac_type ;; +esac + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_int64_t" != no && break + done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_int64_t" >&5 +echo "${ECHO_T}$ac_cv_c_int64_t" >&6; } + case $ac_cv_c_int64_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int64_t $ac_cv_c_int64_t +_ACEOF +;; + esac + + + { echo "$as_me:$LINENO: checking for uint32_t" >&5 +echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; } +if test "${ac_cv_c_uint32_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_uint32_t=no + for ac_type in 'uint32_t' 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) -1 >> (32 - 1) == 1)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + case $ac_type in + uint32_t) ac_cv_c_uint32_t=yes ;; + *) ac_cv_c_uint32_t=$ac_type ;; +esac + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_uint32_t" != no && break + done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_uint32_t" >&5 +echo "${ECHO_T}$ac_cv_c_uint32_t" >&6; } + case $ac_cv_c_uint32_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<\_ACEOF +#define _UINT32_T 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define uint32_t $ac_cv_c_uint32_t +_ACEOF +;; + esac + + + { echo "$as_me:$LINENO: checking for uint64_t" >&5 +echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; } +if test "${ac_cv_c_uint64_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_uint64_t=no + for ac_type in 'uint64_t' 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) -1 >> (64 - 1) == 1)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + case $ac_type in + uint64_t) ac_cv_c_uint64_t=yes ;; + *) ac_cv_c_uint64_t=$ac_type ;; +esac + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_uint64_t" != no && break + done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_uint64_t" >&5 +echo "${ECHO_T}$ac_cv_c_uint64_t" >&6; } + case $ac_cv_c_uint64_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<\_ACEOF +#define _UINT64_T 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define uint64_t $ac_cv_c_uint64_t +_ACEOF +;; + esac + { echo "$as_me:$LINENO: checking for ssize_t" >&5 echo $ECHO_N "checking for ssize_t... $ECHO_C" >&6; } if test "${ac_cv_type_ssize_t+set}" = set; then Index: Python/marshal.c =================================================================== --- Python/marshal.c (revision 67111) +++ Python/marshal.c (working copy) @@ -11,6 +11,8 @@ #include "code.h" #include "marshal.h" +#define ABS(x) ((x) < 0 ? -(x) : (x)) + /* High water mark to determine when the marshalled object is dangerously deep * and risks coring the interpreter. When the object stack gets this deep, * raise an exception instead of continuing. @@ -122,7 +124,57 @@ } #endif +/* We assume that Python longs are stored internally in base some power of + 2**15; for the sake of portability we'll always read and write them in base + exactly 2**15. */ + +#define PyLong_MARSHAL_SHIFT 15 +#define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT) +#define PyLong_MARSHAL_MASK (PyLong_MARSHAL_BASE - 1) +#if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0 +#error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT" +#endif +#define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT) + static void +w_PyLong(const PyLongObject *ob, WFILE *p) +{ + Py_ssize_t i, j, n, l; + digit d; + + w_byte(TYPE_LONG, p); + if (Py_SIZE(ob) == 0) { + w_long((long)0, p); + return; + } + + /* set l to number of base PyLong_MARSHAL_BASE digits */ + n = ABS(Py_SIZE(ob)); + l = (n-1) * PyLong_MARSHAL_RATIO; + d = ob->ob_digit[n-1]; + assert(d != 0); /* a PyLong is always normalized */ + do { + d >>= PyLong_MARSHAL_SHIFT; + l++; + } while (d != 0); + w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p); + + for (i=0; i < n-1; i++) { + d = ob->ob_digit[i]; + for (j=0; j < PyLong_MARSHAL_RATIO; j++) { + w_short(d & PyLong_MARSHAL_MASK, p); + d >>= PyLong_MARSHAL_SHIFT; + } + assert (d == 0); + } + d = ob->ob_digit[n-1]; + do { + w_short(d & PyLong_MARSHAL_MASK, p); + d >>= PyLong_MARSHAL_SHIFT; + } while (d != 0); +} + +static void w_object(PyObject *v, WFILE *p) { Py_ssize_t i, n; @@ -155,14 +207,8 @@ if ((x == -1) && PyErr_Occurred()) { PyLongObject *ob = (PyLongObject *)v; PyErr_Clear(); - w_byte(TYPE_LONG, p); - n = Py_SIZE(ob); - w_long((long)n, p); - if (n < 0) - n = -n; - for (i = 0; i < n; i++) - w_short(ob->ob_digit[i], p); - } + w_PyLong(ob, p); + } else { #if SIZEOF_LONG > 4 long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31); @@ -481,6 +527,55 @@ } static PyObject * +r_PyLong(RFILE *p) +{ + PyLongObject *ob; + int size, i, j, md; + long n; + digit d; + + n = r_long(p); + if (n == 0) + return (PyObject *)_PyLong_New(0); + if (n < -INT_MAX || n > INT_MAX) + goto bad_data; + + size = 1 + (ABS(n)-1) / PyLong_MARSHAL_RATIO; + ob = _PyLong_New(size); + if (ob == NULL) + return NULL; + Py_SIZE(ob) = n > 0 ? size : -size; + + for (i = 0; i < size-1; i++) { + d = 0; + for (j=0; j < PyLong_MARSHAL_RATIO; j++) { + md = r_short(p); + if (md < 0 || md > PyLong_MARSHAL_BASE) { + Py_DECREF(ob); + goto bad_data; + } + d += (digit)md << j*PyLong_MARSHAL_SHIFT; + } + ob->ob_digit[i] = d; + } + d = 0; + for (j=0; j < (ABS(n)-1)%PyLong_MARSHAL_RATIO + 1; j++) { + md = r_short(p); + if (md < 0 || md > PyLong_MARSHAL_BASE) { + Py_DECREF(ob); + goto bad_data; + } + d += (digit)md << (j*PyLong_MARSHAL_SHIFT); + } + ob->ob_digit[size-1] = d; + return (PyObject *)ob; + bad_data: + PyErr_SetString(PyExc_ValueError, "bad marshal data"); + return NULL; +} + + +static PyObject * r_object(RFILE *p) { /* NULL is a valid return value, it does not necessarily means that @@ -544,38 +639,8 @@ break; case TYPE_LONG: - { - int size; - PyLongObject *ob; - n = r_long(p); - if (n < -INT_MAX || n > INT_MAX) { - PyErr_SetString(PyExc_ValueError, - "bad marshal data"); - retval = NULL; - break; - } - size = n<0 ? -n : n; - ob = _PyLong_New(size); - if (ob == NULL) { - retval = NULL; - break; - } - Py_SIZE(ob) = n; - for (i = 0; i < size; i++) { - int digit = r_short(p); - if (digit < 0) { - Py_DECREF(ob); - PyErr_SetString(PyExc_ValueError, - "bad marshal data"); - ob = NULL; - break; - } - if (ob != NULL) - ob->ob_digit[i] = digit; - } - retval = (PyObject *)ob; - break; - } + retval = r_PyLong(p); + break; case TYPE_FLOAT: { Index: Python/sysmodule.c =================================================================== --- Python/sysmodule.c (revision 67111) +++ Python/sysmodule.c (working copy) @@ -1012,6 +1012,7 @@ Static objects:\n\ \n\ float_info -- a dict with information about the float implementation.\n\ +int_info -- a struct sequence with information about the int implementation.\n\ maxsize -- the largest supported length of containers.\n\ maxunicode -- the largest supported character\n\ builtin_module_names -- tuple of module names built into this interpreter\n\ @@ -1321,6 +1322,8 @@ PyLong_FromSsize_t(PY_SSIZE_T_MAX)); SET_SYS_FROM_STRING("float_info", PyFloat_GetInfo()); + SET_SYS_FROM_STRING("int_info", + PyLong_GetInfo()); SET_SYS_FROM_STRING("maxunicode", PyLong_FromLong(PyUnicode_GetMax())); SET_SYS_FROM_STRING("builtin_module_names", Index: Include/longintrepr.h =================================================================== --- Include/longintrepr.h (revision 67111) +++ Include/longintrepr.h (working copy) @@ -18,15 +18,29 @@ And, at some places it is assumed that MASK fits in an int, as well. long_pow() requires that SHIFT be divisible by 5. */ +#if HAVE_STDINT_H +#include +#endif + +#if (defined UINT32_MAX || defined uint32_t) && \ + (defined UINT64_MAX || defined uint64_t) && \ + (defined INT32_MAX || defined int32_t) && \ + (defined INT64_MAX || defined int64_t) +typedef uint32_t digit; +typedef int32_t sdigit; /* signed variant of digit */ +typedef uint64_t twodigits; +typedef int64_t stwodigits; /* signed variant of twodigits */ +#define PyLong_SHIFT 30 +#else typedef unsigned short digit; -typedef unsigned int wdigit; /* digit widened to parameter size */ -#define BASE_TWODIGITS_TYPE long -typedef unsigned BASE_TWODIGITS_TYPE twodigits; -typedef BASE_TWODIGITS_TYPE stwodigits; /* signed variant of twodigits */ +typedef short sdigit; /* signed variant of digit */ +typedef unsigned long twodigits; +typedef long stwodigits; /* signed variant of twodigits */ +#define PyLong_SHIFT 15 +#endif -#define PyLong_SHIFT 15 #define PyLong_BASE ((digit)1 << PyLong_SHIFT) -#define PyLong_MASK ((int)(PyLong_BASE - 1)) +#define PyLong_MASK (PyLong_BASE - 1) #if PyLong_SHIFT % 5 != 0 #error "longobject.c requires that SHIFT be divisible by 5" Index: Include/longobject.h =================================================================== --- Include/longobject.h (revision 67111) +++ Include/longobject.h (working copy) @@ -26,6 +26,7 @@ PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); +PyAPI_FUNC(PyObject *) PyLong_GetInfo(void); /* It may be useful in the future. I've added it in the PyInt -> PyLong cleanup to keep the extra information. [CH] */ Index: configure.in =================================================================== --- configure.in (revision 67111) +++ configure.in (working copy) @@ -1282,6 +1282,10 @@ AC_TYPE_SIGNAL AC_TYPE_SIZE_T AC_TYPE_UID_T +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T AC_CHECK_TYPE(ssize_t, AC_DEFINE(HAVE_SSIZE_T, 1, Define if your compiler provides ssize_t),,) Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (revision 67111) +++ Objects/longobject.c (working copy) @@ -4,6 +4,7 @@ #include "Python.h" #include "longintrepr.h" +#include "structseq.h" #include @@ -14,8 +15,8 @@ #define NSMALLNEGINTS 5 #endif -#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(x)->ob_digit[0] : \ - (Py_SIZE(x) == 0 ? 0 : (x)->ob_digit[0])) +#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \ + (Py_SIZE(x) == 0 ? 0 : (sdigit)(x)->ob_digit[0])) #define ABS(x) ((x) < 0 ? -(x) : (x)) #if NSMALLNEGINTS + NSMALLPOSINTS > 0 @@ -92,8 +93,8 @@ /* Forward */ static PyLongObject *long_normalize(PyLongObject *); -static PyLongObject *mul1(PyLongObject *, wdigit); -static PyLongObject *muladd1(PyLongObject *, wdigit, wdigit); +static PyLongObject *mul1(PyLongObject *, digit); +static PyLongObject *muladd1(PyLongObject *, digit, digit); static PyLongObject *divrem1(PyLongObject *, digit, digit *); #define SIGCHECK(PyTryBlock) \ @@ -203,17 +204,6 @@ return (PyObject*)v; } - /* 2 digits */ - if (!(ival >> 2*PyLong_SHIFT)) { - v = _PyLong_New(2); - if (v) { - Py_SIZE(v) = 2*sign; - v->ob_digit[0] = (digit)ival & PyLong_MASK; - v->ob_digit[1] = ival >> PyLong_SHIFT; - } - return (PyObject*)v; - } - /* Larger numbers: loop to determine number of digits */ t = abs_ival; while (t) { @@ -361,7 +351,7 @@ switch (i) { case -1: - res = -v->ob_digit[0]; + res = -(sdigit)v->ob_digit[0]; break; case 0: res = 0; @@ -436,7 +426,7 @@ v = (PyLongObject *)vv; i = Py_SIZE(v); switch (i) { - case -1: return -v->ob_digit[0]; + case -1: return -(sdigit)v->ob_digit[0]; case 0: return 0; case 1: return v->ob_digit[0]; } @@ -739,7 +729,7 @@ /* Because we're going LSB to MSB, thisbyte is more significant than what's already in accum, so needs to be prepended to accum. */ - accum |= thisbyte << accumbits; + accum |= (twodigits)thisbyte << accumbits; accumbits += 8; if (accumbits >= PyLong_SHIFT) { /* There's enough to fill a Python digit. */ @@ -822,7 +812,7 @@ /* Because we're going LSB to MSB, thisdigit is more significant than what's already in accum, so needs to be prepended to accum. */ - accum |= thisdigit << accumbits; + accum |= (twodigits)thisdigit << accumbits; accumbits += PyLong_SHIFT; /* The most-significant digit may be (probably is) at least @@ -1229,7 +1219,7 @@ v = (PyLongObject*)vv; switch(Py_SIZE(v)) { - case -1: return -v->ob_digit[0]; + case -1: return -(sdigit)v->ob_digit[0]; case 0: return 0; case 1: return v->ob_digit[0]; } @@ -1409,7 +1399,7 @@ /* Multiply by a single digit, ignoring the sign. */ static PyLongObject * -mul1(PyLongObject *a, wdigit n) +mul1(PyLongObject *a, digit n) { return muladd1(a, n, (digit)0); } @@ -1417,7 +1407,7 @@ /* Multiply by a single digit and add a single digit, ignoring the sign. */ static PyLongObject * -muladd1(PyLongObject *a, wdigit n, wdigit extra) +muladd1(PyLongObject *a, digit n, digit extra) { Py_ssize_t size_a = ABS(Py_SIZE(a)); PyLongObject *z = _PyLong_New(size_a+1); @@ -1453,7 +1443,7 @@ digit hi; rem = (rem << PyLong_SHIFT) + *--pin; *--pout = hi = (digit)(rem / n); - rem -= hi * n; + rem -= (twodigits)hi * n; } return (digit)rem; } @@ -1712,7 +1702,7 @@ while (--p >= start) { int k = _PyLong_DigitValue[Py_CHARMASK(*p)]; assert(k >= 0 && k < base); - accum |= (twodigits)(k << bits_in_accum); + accum |= (twodigits)k << bits_in_accum; bits_in_accum += bits_per_char; if (bits_in_accum >= PyLong_SHIFT) { *pdigit++ = (digit)(accum & PyLong_MASK); @@ -2254,7 +2244,7 @@ of mapping keys will turn out weird */ i = Py_SIZE(v); switch(i) { - case -1: return v->ob_digit[0]==1 ? -2 : -v->ob_digit[0]; + case -1: return v->ob_digit[0]==1 ? -2 : -(sdigit)v->ob_digit[0]; case 0: return 0; case 1: return v->ob_digit[0]; } @@ -2270,7 +2260,8 @@ resulting x is nonzero if and only if v is. */ while (--i >= 0) { /* Force a native long #-bits (32 or 64) circular shift */ - x = ((x << PyLong_SHIFT) & ~PyLong_MASK) | ((x >> LONG_BIT_PyLong_SHIFT) & PyLong_MASK); + x = ((x << PyLong_SHIFT) & ~(long)PyLong_MASK) | + ((x >> LONG_BIT_PyLong_SHIFT) & PyLong_MASK); x += v->ob_digit[i]; /* If the addition above overflowed (thinking of x as unsigned), we compensate by incrementing. This preserves @@ -2841,10 +2832,34 @@ CHECK_BINOP(a, b); + /* fast path for single-digit multiplication */ if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) { - PyObject *r; - r = PyLong_FromLong(MEDIUM_VALUE(a)*MEDIUM_VALUE(b)); - return r; + /* XXX benchmark this! Is is worth keeping? */ + twodigits absv; + int sign; + PyLongObject *v; + sign = Py_SIZE(a) * Py_SIZE(b); + if (sign == 0) + return PyLong_FromLong(0L); + absv = (twodigits)a->ob_digit[0] * b->ob_digit[0]; + if (absv < PyLong_BASE) { + CHECK_SMALL_INT((sdigit)(sign*absv)); + v = _PyLong_New(1); + if (v != NULL) { + Py_SIZE(v) = sign; + v->ob_digit[0] = absv; + } + } + else { + v = _PyLong_New(2); + if (v != NULL) { + Py_SIZE(v) = 2*sign; + v->ob_digit[0] = (digit)(absv & PyLong_MASK); + assert(absv >>= 2*PyLong_SHIFT == 0); + v->ob_digit[1] = (digit)(absv >> PyLong_SHIFT); + } + } + return (PyObject *)v; } z = k_mul(a, b); @@ -3792,6 +3807,44 @@ PyObject_Del, /* tp_free */ }; +static PyTypeObject Int_InfoType; + +PyDoc_STRVAR(int_info__doc__, +"sys.int_info\n\ +\n\ +A struct sequence that holds information about Python's\n\ +internal representation of integers. The attributes are read only."); + +static PyStructSequence_Field int_info_fields[] = { + {"bits_per_digit", "number of bits held in each digit"}, + {"sizeof_digit", "size in bytes of the C type used to " + "represent a digit"}, + {0} +}; + +static PyStructSequence_Desc int_info_desc = { + "sys.int_info", /* name */ + int_info__doc__, /* doc */ + int_info_fields, /* fields */ + 2 /* number of fields */ +}; + +PyObject * +PyLong_GetInfo(void) +{ + PyObject* int_info; + int_info = PyStructSequence_New(&Int_InfoType); + if (int_info == NULL) + return NULL; + PyStructSequence_SET_ITEM(int_info, 0, PyLong_FromLong(PyLong_SHIFT)); + PyStructSequence_SET_ITEM(int_info, 1, PyLong_FromLong(sizeof(digit))); + if (PyErr_Occurred()) { + Py_CLEAR(int_info); + return NULL; + } + return int_info; +} + int _PyLong_Init(void) { @@ -3824,6 +3877,10 @@ v->ob_digit[0] = abs(ival); } #endif + /* initialize int_info */ + if (Int_InfoType.tp_name == 0) + PyStructSequence_InitType(&Int_InfoType, &int_info_desc); + return 1; } Index: Doc/library/sys.rst =================================================================== --- Doc/library/sys.rst (revision 67111) +++ Doc/library/sys.rst (working copy) @@ -413,6 +413,23 @@ same information. +.. data:: int_info + + A struct sequence that holds information about Python's + internal representation of integers. The attributes are read only. + + +-------------------------+----------------------------------------------+ + | attribute | explanation | + +=========================+==============================================+ + | :const:`bits_per_digit` | number of bits held in each digit. Python | + | | integers are stored internally in base | + | | ``2**int_info.bits_per_digit`` | + +-------------------------+----------------------------------------------+ + | :const:`sizeof_digit` | size in bytes of the C type used to | + | | represent a digit | + +-------------------------+----------------------------------------------+ + + .. function:: intern(string) Enter *string* in the table of "interned" strings and return the interned string Index: Lib/test/test_sys.py =================================================================== --- Lib/test/test_sys.py (revision 67111) +++ Lib/test/test_sys.py (working copy) @@ -291,6 +291,11 @@ self.assert_(isinstance(sys.executable, str)) self.assertEqual(len(sys.float_info), 11) self.assertEqual(sys.float_info.radix, 2) + self.assertEqual(len(sys.int_info), 2) + self.assert_(sys.int_info.bits_per_digit in (15, 30)) + self.assert_(sys.int_info.sizeof_digit >= 2) + if sys.int_info.bits_per_digit == 30: + self.assert_(sys.int_info.sizeof_digit == 4) self.assert_(isinstance(sys.hexversion, int)) self.assert_(isinstance(sys.maxsize, int)) self.assert_(isinstance(sys.maxunicode, int)) @@ -383,6 +388,7 @@ if hasattr(sys, "gettotalrefcount"): self.header += '2P' self.vheader += '2P' + self.longdigit = sys.int_info.sizeof_digit import _testcapi self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD self.file = open(test.support.TESTFN, 'wb') @@ -417,7 +423,7 @@ size = self.calcsize gc_header_size = self.gc_headsize # bool objects are not gc tracked - self.assertEqual(sys.getsizeof(True), size(vh) + self.H) + self.assertEqual(sys.getsizeof(True), size(vh) + self.longdigit) # but lists are self.assertEqual(sys.getsizeof([]), size(vh + 'PP') + gc_header_size) @@ -425,8 +431,8 @@ h = self.header vh = self.vheader size = self.calcsize - self.assertEqual(sys.getsizeof(True), size(vh) + self.H) - self.assertEqual(sys.getsizeof(True, -1), size(vh) + self.H) + self.assertEqual(sys.getsizeof(True), size(vh) + self.longdigit) + self.assertEqual(sys.getsizeof(True, -1), size(vh) + self.longdigit) def test_objecttypes(self): # check all types defined in Objects/ @@ -435,7 +441,7 @@ size = self.calcsize check = self.check_sizeof # bool - check(True, size(vh) + self.H) + check(True, size(vh) + self.longdigit) # buffer # XXX # builtin_function_or_method @@ -553,11 +559,12 @@ check(reversed([]), size(h + 'lP')) # long check(0, size(vh)) - check(1, size(vh) + self.H) - check(-1, size(vh) + self.H) - check(32768, size(vh) + 2*self.H) - check(32768*32768-1, size(vh) + 2*self.H) - check(32768*32768, size(vh) + 3*self.H) + check(1, size(vh) + self.longdigit) + check(-1, size(vh) + self.longdigit) + PyLong_BASE = 2**sys.int_info.bits_per_digit + check(PyLong_BASE, size(vh) + 2*self.longdigit) + check(PyLong_BASE**2-1, size(vh) + 2*self.longdigit) + check(PyLong_BASE**2, size(vh) + 3*self.longdigit) # memory check(memoryview(b''), size(h + 'P PP2P2i5P')) # module Index: pyconfig.h.in =================================================================== --- pyconfig.h.in (revision 67111) +++ pyconfig.h.in (working copy) @@ -58,6 +58,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_BLUETOOTH_H +/* Define if mbstowcs(NULL, "text", 0) does not return the number of wide + chars that would be converted. */ +#undef HAVE_BROKEN_MBSTOWCS + /* Define if nice() returns success/failure instead of the new priority. */ #undef HAVE_BROKEN_NICE @@ -357,7 +361,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LIBINTL_H -/* Define to 1 if you have the `readline' library (-lreadline). */ +/* Define if you have the readline library (-lreadline). */ #undef HAVE_LIBREADLINE /* Define to 1 if you have the `resolv' library (-lresolv). */ @@ -800,10 +804,6 @@ /* Define to 1 if you have the `wcsxfrm' function. */ #undef HAVE_WCSXFRM -/* Define if mbstowcs(NULL, "text", 0) does not return the number of - wide chars that would be converted */ -#undef HAVE_BROKEN_MBSTOWCS - /* Define if tzset() actually switches the local timezone in a meaningful way. */ #undef HAVE_WORKING_TZSET @@ -1024,6 +1024,16 @@ /* Define to force use of thread-safe errno, h_errno, and other functions */ #undef _REENTRANT +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef was allowed, the + #define below would cause a syntax error. */ +#undef _UINT32_T + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef was allowed, the + #define below would cause a syntax error. */ +#undef _UINT64_T + /* Define to the level of X/Open that your system supports */ #undef _XOPEN_SOURCE @@ -1050,6 +1060,14 @@ /* Define to `int' if doesn't define. */ #undef gid_t +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef int32_t + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef int64_t + /* Define to `int' if does not define. */ #undef mode_t @@ -1071,6 +1089,14 @@ /* Define to `int' if doesn't define. */ #undef uid_t +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef uint32_t + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef uint64_t + /* Define to empty if the keyword does not work. */ #undef volatile