[pypy-commit] pypy default: Tkinter: Add support for bignum numbers.

amauryfa noreply at buildbot.pypy.org
Mon Jun 15 09:33:17 CEST 2015


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r78101:dad26a9f1b29
Date: 2015-06-14 23:48 +0200
http://bitbucket.org/pypy/pypy/changeset/dad26a9f1b29/

Log:	Tkinter: Add support for bignum numbers.

diff --git a/lib_pypy/_tkinter/app.py b/lib_pypy/_tkinter/app.py
--- a/lib_pypy/_tkinter/app.py
+++ b/lib_pypy/_tkinter/app.py
@@ -141,6 +141,7 @@
 
         Tcl_AppInit(self)
         # EnableEventHook()
+        self._typeCache.add_extra_types(self)
         return self
 
     def __del__(self):
diff --git a/lib_pypy/_tkinter/tclobj.py b/lib_pypy/_tkinter/tclobj.py
--- a/lib_pypy/_tkinter/tclobj.py
+++ b/lib_pypy/_tkinter/tclobj.py
@@ -1,6 +1,7 @@
 # TclObject, conversions with Python objects
 
 from .tklib_cffi import ffi as tkffi, lib as tklib
+import binascii
 
 class TypeCache(object):
     def __init__(self):
@@ -8,10 +9,18 @@
         self.ByteArrayType = tklib.Tcl_GetObjType("bytearray")
         self.DoubleType = tklib.Tcl_GetObjType("double")
         self.IntType = tklib.Tcl_GetObjType("int")
+        self.BigNumType = None
         self.ListType = tklib.Tcl_GetObjType("list")
         self.ProcBodyType = tklib.Tcl_GetObjType("procbody")
         self.StringType = tklib.Tcl_GetObjType("string")
 
+    def add_extra_types(self, app):
+        # Some types are not registered in Tcl.
+        result = app.call('expr', '2**63')
+        typePtr = AsObj(result).typePtr
+        if tkffi.string(typePtr.name) == "bignum":
+            self.BigNumType = typePtr
+
 
 def FromTclString(s):
     # If the result contains any bytes with the top bit set, it's
@@ -30,6 +39,24 @@
     return s
 
 
+# Only when tklib.HAVE_LIBTOMMATH!
+def FromBignumObj(app, value):
+    bigValue = tkffi.new("mp_int*")
+    if tklib.Tcl_GetBignumFromObj(app.interp, value, bigValue) != tklib.TCL_OK:
+        app.raiseTclError()
+    try:
+        numBytes = tklib.mp_unsigned_bin_size(bigValue)
+        buf = tkffi.new("unsigned char[]", numBytes)
+        bufSize_ptr = tkffi.new("unsigned long*", numBytes)
+        if tklib.mp_to_unsigned_bin_n(
+                bigValue, buf, bufSize_ptr) != tklib.MP_OKAY:
+            raise MemoryError
+        bytes = tkffi.buffer(buf)[0:bufSize_ptr[0]]
+        sign = -1 if bigValue.sign == tklib.MP_NEG else 1
+        return sign * int(binascii.hexlify(bytes), 16)
+    finally:
+        tklib.mp_clear(bigValue)
+
 def FromObj(app, value):
     """Convert a TclObj pointer into a Python object."""
     typeCache = app._typeCache
@@ -37,17 +64,19 @@
         buf = tkffi.buffer(value.bytes, value.length)
         return FromTclString(buf[:])
 
-    elif value.typePtr == typeCache.BooleanType:
+    if value.typePtr == typeCache.BooleanType:
         return bool(value.internalRep.longValue)
-    elif value.typePtr == typeCache.ByteArrayType:
+    if value.typePtr == typeCache.ByteArrayType:
         size = tkffi.new('int*')
         data = tklib.Tcl_GetByteArrayFromObj(value, size)
         return tkffi.buffer(data, size[0])[:]
-    elif value.typePtr == typeCache.DoubleType:
+    if value.typePtr == typeCache.DoubleType:
         return value.internalRep.doubleValue
-    elif value.typePtr == typeCache.IntType:
+    if value.typePtr == typeCache.IntType:
         return value.internalRep.longValue
-    elif value.typePtr == typeCache.ListType:
+    if value.typePtr == typeCache.BigNumType and tklib.HAVE_LIBTOMMATH:
+        return FromBignumObj(app, value)
+    if value.typePtr == typeCache.ListType:
         size = tkffi.new('int*')
         status = tklib.Tcl_ListObjLength(app.interp, value, size)
         if status == tklib.TCL_ERROR:
@@ -61,9 +90,9 @@
                 app.raiseTclError()
             result.append(FromObj(app, tcl_elem[0]))
         return tuple(result)
-    elif value.typePtr == typeCache.ProcBodyType:
+    if value.typePtr == typeCache.ProcBodyType:
         pass  # fall through and return tcl object.
-    elif value.typePtr == typeCache.StringType:
+    if value.typePtr == typeCache.StringType:
         buf = tklib.Tcl_GetUnicode(value)
         length = tklib.Tcl_GetCharLength(value)
         buf = tkffi.buffer(tkffi.cast("char*", buf), length*2)[:]
diff --git a/lib_pypy/_tkinter/tklib_build.py b/lib_pypy/_tkinter/tklib_build.py
--- a/lib_pypy/_tkinter/tklib_build.py
+++ b/lib_pypy/_tkinter/tklib_build.py
@@ -46,14 +46,16 @@
 
 TK_HEX_VERSION = config_lib.TK_HEX_VERSION
 
-HAVE_LIBTOMMATH = ((0x08050208 <= TK_HEX_VERSION < 0x08060000) or
-                   (0x08060200 <= TK_HEX_VERSION))
+HAVE_LIBTOMMATH = int((0x08050208 <= TK_HEX_VERSION < 0x08060000) or
+                      (0x08060200 <= TK_HEX_VERSION))
 
 tkffi = FFI()
 
 tkffi.cdef("""
 char *get_tk_version();
 char *get_tcl_version();
+#define HAVE_LIBTOMMATH ...
+
 #define TCL_READABLE ...
 #define TCL_WRITABLE ...
 #define TCL_EXCEPTION ...
@@ -162,13 +164,34 @@
 void Tcl_FindExecutable(char *argv0);
 """)
 
+if HAVE_LIBTOMMATH:
+    tkffi.cdef("""
+#define MP_OKAY ...
+#define MP_NEG ...
+typedef struct {
+    int sign;
+    ...;
+} mp_int;
+
+int Tcl_GetBignumFromObj(Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value);
+
+int mp_unsigned_bin_size(mp_int *a);
+int mp_to_unsigned_bin_n(mp_int * a, unsigned char *b, unsigned long *outlen);
+void mp_clear(mp_int *a);
+""")
+
 tkffi.set_source("_tkinter.tklib_cffi", """
+#define HAVE_LIBTOMMATH %(HAVE_LIBTOMMATH)s
 #include <tcl.h>
 #include <tk.h>
 
+#if HAVE_LIBTOMMATH
+#include <tclTomMath.h>
+#endif 
+
 char *get_tk_version() { return TK_VERSION; }
 char *get_tcl_version() { return TCL_VERSION; }
-""",
+""" % globals(),
 include_dirs=incdirs,
 libraries=linklibs,
 library_dirs = libdirs


More information about the pypy-commit mailing list