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: 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: 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/abstract.c =================================================================== --- Objects/abstract.c (revision 67111) +++ Objects/abstract.c (working copy) @@ -3,7 +3,6 @@ #include "Python.h" #include #include "structmember.h" /* we need the offsetof() macro from there */ -#include "longintrepr.h" Index: Objects/boolobject.c =================================================================== --- Objects/boolobject.c (revision 67111) +++ Objects/boolobject.c (working copy) @@ -1,7 +1,6 @@ /* Boolean type, a subtype of int */ #include "Python.h" -#include "longintrepr.h" /* We define bool_repr to return "False" or "True" */ Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (revision 67111) +++ Objects/longobject.c (working copy) @@ -1,3 +1,4 @@ +/* search for (int) */ /* Long (arbitrary precision) integer object implementation */ /* XXX The functional organization of this file is terrible */ @@ -4,6 +5,7 @@ #include "Python.h" #include "longintrepr.h" +#include "structseq.h" #include @@ -14,8 +16,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 @@ -51,7 +53,7 @@ maybe_small_long(PyLongObject *v) { if (v && ABS(Py_SIZE(v)) <= 1) { - int ival = MEDIUM_VALUE(v); + sdigit ival = MEDIUM_VALUE(v); if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { Py_DECREF(v); return (PyLongObject *)get_small_int(ival); @@ -90,12 +92,6 @@ #define MAX(x, y) ((x) < (y) ? (y) : (x)) #define MIN(x, y) ((x) > (y) ? (y) : (x)) -/* Forward */ -static PyLongObject *long_normalize(PyLongObject *); -static PyLongObject *mul1(PyLongObject *, wdigit); -static PyLongObject *muladd1(PyLongObject *, wdigit, wdigit); -static PyLongObject *divrem1(PyLongObject *, digit, digit *); - #define SIGCHECK(PyTryBlock) \ if (--_Py_Ticker < 0) { \ _Py_Ticker = _Py_CheckInterval; \ @@ -155,7 +151,7 @@ if (i < 0) i = -(i); if (i < 2) { - int ival = src->ob_digit[0]; + sdigit ival = src->ob_digit[0]; if (Py_SIZE(src) < 0) ival = -ival; CHECK_SMALL_INT(ival); @@ -175,7 +171,7 @@ PyLong_FromLong(long ival) { PyLongObject *v; - unsigned long abs_ival; + unsigned long abs_ival; unsigned long t; /* unsigned so >> doesn't propagate sign bit */ int ndigits = 0; int sign = 1; @@ -194,26 +190,15 @@ } /* Fast path for single-digits ints */ - if (!(ival>>PyLong_SHIFT)) { + if (!(abs_ival>>PyLong_SHIFT)) { v = _PyLong_New(1); if (v) { Py_SIZE(v) = sign; - v->ob_digit[0] = ival; + v->ob_digit[0] = abs_ival; } 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) { @@ -294,8 +279,8 @@ return NULL; frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1); for (i = ndig; --i >= 0; ) { - long bits = (long)frac; - v->ob_digit[i] = (digit) bits; + digit bits = (digit)frac; + v->ob_digit[i] = bits; frac = frac - (double)bits; frac = ldexp(frac, PyLong_SHIFT); } @@ -361,7 +346,7 @@ switch (i) { case -1: - res = -v->ob_digit[0]; + res = -(sdigit)v->ob_digit[0]; break; case 0: res = 0; @@ -436,7 +421,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]; } @@ -664,9 +649,9 @@ int incr; /* direction to move pstartbyte */ const unsigned char* pendbyte; /* MSB of bytes */ size_t numsignificantbytes; /* number of bytes that matter */ - size_t ndigits; /* number of Python long digits */ + Py_ssize_t ndigits; /* number of Python long digits */ PyLongObject* v; /* result */ - int idigit = 0; /* next free index in v->ob_digit */ + Py_ssize_t idigit = 0; /* next free index in v->ob_digit */ if (n == 0) return PyLong_FromLong(0L); @@ -709,12 +694,16 @@ } /* How many Python long digits do we need? We have - 8*numsignificantbytes bits, and each Python long digit has PyLong_SHIFT - bits, so it's the ceiling of the quotient. */ + 8*numsignificantbytes bits, and each Python long digit has + PyLong_SHIFT bits, so it's the ceiling of the quotient. */ + /* catch overflow before it happens */ + if (numsignificantbytes > (SIZE_T_MAX - PyLong_SHIFT) / 8) { + PyErr_SetString(PyExc_OverflowError, + "byte array too long to convert to int"); + return NULL; + } ndigits = (numsignificantbytes * 8 + PyLong_SHIFT - 1) / PyLong_SHIFT; - if (ndigits > (size_t)INT_MAX) - return PyErr_NoMemory(); - v = _PyLong_New((int)ndigits); + v = _PyLong_New(ndigits); if (v == NULL) return NULL; @@ -739,12 +728,13 @@ /* 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. */ - assert(idigit < (int)ndigits); - v->ob_digit[idigit] = (digit)(accum & PyLong_MASK); + assert(idigit < ndigits); + v->ob_digit[idigit] = (digit)(accum & + PyLong_MASK); ++idigit; accum >>= PyLong_SHIFT; accumbits -= PyLong_SHIFT; @@ -753,7 +743,7 @@ } assert(accumbits < PyLong_SHIFT); if (accumbits) { - assert(idigit < (int)ndigits); + assert(idigit < ndigits); v->ob_digit[idigit] = (digit)accum; ++idigit; } @@ -768,8 +758,8 @@ unsigned char* bytes, size_t n, int little_endian, int is_signed) { - int i; /* index into v->ob_digit */ - Py_ssize_t ndigits; /* |v->ob_size| */ + Py_ssize_t i; /* index into v->ob_digit */ + Py_ssize_t ndigits; /* |v->ob_size| */ twodigits accum; /* sliding register */ unsigned int accumbits; /* # bits in accum */ int do_twos_comp; /* store 2's-comp? is_signed and v < 0 */ @@ -805,15 +795,15 @@ /* Copy over all the Python digits. It's crucial that every Python digit except for the MSD contribute - exactly PyLong_SHIFT bits to the total, so first assert that the long is - normalized. */ + exactly PyLong_SHIFT bits to the total, so first assert that the + long is normalized. */ assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); j = 0; accum = 0; accumbits = 0; carry = do_twos_comp ? 1 : 0; for (i = 0; i < ndigits; ++i) { - twodigits thisdigit = v->ob_digit[i]; + digit thisdigit = v->ob_digit[i]; if (do_twos_comp) { thisdigit = (thisdigit ^ PyLong_MASK) + carry; carry = thisdigit >> PyLong_SHIFT; @@ -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 @@ -833,10 +823,11 @@ * make sure at least one sign bit gets stored. * First shift conceptual sign bit to real sign bit. */ - stwodigits s = (stwodigits)(thisdigit << - (8*sizeof(stwodigits) - PyLong_SHIFT)); + sdigit s = (sdigit)(thisdigit << + (8*sizeof(digit) - PyLong_SHIFT)); unsigned int nsignbits = 0; - while ((s < 0) == do_twos_comp && nsignbits < PyLong_SHIFT) { + while ((s < 0) == do_twos_comp && + nsignbits < PyLong_SHIFT) { ++nsignbits; s <<= 1; } @@ -1229,7 +1220,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]; } @@ -1361,7 +1352,7 @@ static digit v_iadd(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n) { - int i; + Py_ssize_t i; digit carry = 0; assert(m >= n); @@ -1387,7 +1378,7 @@ static digit v_isub(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n) { - int i; + Py_ssize_t i; digit borrow = 0; assert(m >= n); @@ -1406,18 +1397,10 @@ return borrow; } -/* Multiply by a single digit, ignoring the sign. */ - -static PyLongObject * -mul1(PyLongObject *a, wdigit n) -{ - return muladd1(a, n, (digit)0); -} - /* 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); @@ -1435,6 +1418,14 @@ return long_normalize(z); } +/* Multiply by a single digit, ignoring the sign. */ + +static PyLongObject * +mul1(PyLongObject *a, digit n) +{ + return muladd1(a, n, (digit)0); +} + /* 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 @@ -1453,7 +1444,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 +1703,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); @@ -2036,8 +2027,6 @@ static PyLongObject *x_divrem (PyLongObject *, PyLongObject *, PyLongObject **); static PyObject *long_long(PyObject *v); -static int long_divrem(PyLongObject *, PyLongObject *, - PyLongObject **, PyLongObject **); /* Long division with remainder, top-level routine */ @@ -2122,7 +2111,7 @@ digit vj = (j >= size_v) ? 0 : v->ob_digit[j]; twodigits q; stwodigits carry = 0; - int i; + Py_ssize_t i; SIGCHECK({ Py_DECREF(a); @@ -2254,7 +2243,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 +2259,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 @@ -2293,7 +2283,7 @@ { Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b)); PyLongObject *z; - int i; + Py_ssize_t i; digit carry = 0; /* Ensure a is the larger of the two: */ @@ -2841,10 +2831,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); @@ -3363,9 +3377,8 @@ { digit maska, maskb; /* 0 or PyLong_MASK */ int negz; - Py_ssize_t size_a, size_b, size_z; + Py_ssize_t size_a, size_b, size_z, i; PyLongObject *z; - int i; digit diga, digb; PyObject *v; @@ -3536,7 +3549,7 @@ /* Since PyLong_FromString doesn't have a length parameter, * check here for possible NULs in the string. */ char *string; - int size = Py_SIZE(x); + Py_ssize_t size = Py_SIZE(x); if (PyByteArray_Check(x)) string = PyByteArray_AS_STRING(x); else @@ -3792,6 +3805,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 +3875,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_long.py =================================================================== --- Lib/test/test_long.py (revision 67111) +++ Lib/test/test_long.py (working copy) @@ -14,7 +14,7 @@ return self.format % self.args # SHIFT should match the value in longintrepr.h for best testing. -SHIFT = 15 +SHIFT = sys.int_info.bits_per_digit BASE = 2 ** SHIFT MASK = BASE - 1 KARATSUBA_CUTOFF = 70 # from longobject.c 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