]> granicus.if.org Git - python/commitdiff
Issue #2616: Implement ctypes.pointer() and ctypes.POINTER() in C for
authorThomas Heller <theller@ctypes.org>
Mon, 14 Apr 2008 16:10:07 +0000 (16:10 +0000)
committerThomas Heller <theller@ctypes.org>
Mon, 14 Apr 2008 16:10:07 +0000 (16:10 +0000)
better performance.

Lib/ctypes/__init__.py
Misc/NEWS
Modules/_ctypes/_ctypes.c
Modules/_ctypes/callproc.c
Modules/_ctypes/ctypes.h

index 7cacdd2f851ecf46b6e7698131d2e7cac7bcb752..41d39dc93f12ef0c51bdd13c866250856078b880 100644 (file)
@@ -242,27 +242,7 @@ _check_size(c_void_p)
 class c_bool(_SimpleCData):
     _type_ = "?"
 
-# This cache maps types to pointers to them.
-_pointer_type_cache = {}
-
-def POINTER(cls):
-    try:
-        return _pointer_type_cache[cls]
-    except KeyError:
-        pass
-    if type(cls) is str:
-        klass = type(_Pointer)("LP_%s" % cls,
-                               (_Pointer,),
-                               {})
-        _pointer_type_cache[id(klass)] = klass
-        return klass
-    else:
-        name = "LP_%s" % cls.__name__
-        klass = type(_Pointer)(name,
-                               (_Pointer,),
-                               {'_type_': cls})
-        _pointer_type_cache[cls] = klass
-    return klass
+from _ctypes import POINTER, pointer, _pointer_type_cache
 
 try:
     from _ctypes import set_conversion_mode
@@ -312,10 +292,6 @@ def SetPointerType(pointer, cls):
     _pointer_type_cache[cls] = pointer
     del _pointer_type_cache[id(pointer)]
 
-
-def pointer(inst):
-    return POINTER(type(inst))(inst)
-
 # XXX Deprecated
 def ARRAY(typ, len):
     return typ * len
index eda3685f0ac1874f7f2d383749798e60af48c3f0..b4077e5af2b8dd4106bbc3527b03aa51ac23a1fc 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -29,6 +29,9 @@ Extensions Modules
 Library
 -------
 
+- Issue #2616: The ctypes.pointer() and ctypes.POINTER() functions are
+  now implemented in C for better performance.
+
 - Issue #2408: The ``_types`` module, which was used as in implementation
   detail of the public ``types`` module, has been removed and replaced by pure
   python code.
index b23c3d8681d21264dda4d25ee3c7dc6bf5aaa713..355fda207f8e713db6c49fcb9ae381d642a5894d 100644 (file)
@@ -128,6 +128,10 @@ bytes(cdata)
 #include "ctypes.h"
 
 PyObject *PyExc_ArgError;
+
+/* This dict maps ctypes types to POINTER types */
+PyObject *_pointer_type_cache;
+
 static PyTypeObject Simple_Type;
 
 /* a callable object used for unpickling */
@@ -5169,6 +5173,12 @@ init_ctypes(void)
        if (!m)
                return;
 
+       _pointer_type_cache = PyDict_New();
+       if (_pointer_type_cache == NULL)
+               return;
+
+       PyModule_AddObject(m, "_pointer_type_cache", (PyObject *)_pointer_type_cache);
+
        _unpickle = PyObject_GetAttrString(m, "_unpickle");
        if (_unpickle == NULL)
                return;
index 783df08bc3e51174a6618e87c761d496084dd356..c5281799de2c63cd621e8e93ac72fa776722dead 100644 (file)
@@ -1600,7 +1600,75 @@ unpickle(PyObject *self, PyObject *args)
        return result;
 }
 
+static PyObject *
+POINTER(PyObject *self, PyObject *cls)
+{
+       PyObject *result;
+       PyTypeObject *typ;
+       PyObject *key;
+       char *buf;
+
+       result = PyDict_GetItem(_pointer_type_cache, cls);
+       if (result) {
+               Py_INCREF(result);
+               return result;
+       }
+       if (PyString_CheckExact(cls)) {
+               buf = alloca(strlen(PyString_AS_STRING(cls)) + 3 + 1);
+               sprintf(buf, "LP_%s", PyString_AS_STRING(cls));
+               result = PyObject_CallFunction((PyObject *)Py_TYPE(&Pointer_Type),
+                                              "s(O){}",
+                                              buf,
+                                              &Pointer_Type);
+               if (result == NULL)
+                       return result;
+               key = PyLong_FromVoidPtr(result);
+       } else if (PyType_Check(cls)) {
+               typ = (PyTypeObject *)cls;
+               buf = alloca(strlen(typ->tp_name) + 3 + 1);
+               sprintf(buf, "LP_%s", typ->tp_name);
+               result = PyObject_CallFunction((PyObject *)Py_TYPE(&Pointer_Type),
+                                              "s(O){sO}",
+                                              buf,
+                                              &Pointer_Type,
+                                              "_type_", cls);
+               if (result == NULL)
+                       return result;
+               Py_INCREF(cls);
+               key = cls;
+       } else {
+               PyErr_SetString(PyExc_TypeError, "must be a ctypes type");
+               return NULL;
+       }
+       if (-1 == PyDict_SetItem(_pointer_type_cache, key, result)) {
+               Py_DECREF(result);
+               Py_DECREF(key);
+               return NULL;
+       }
+       Py_DECREF(key);
+       return result;
+}
+
+static PyObject *
+pointer(PyObject *self, PyObject *arg)
+{
+       PyObject *result;
+       PyObject *typ;
+
+       typ = PyDict_GetItem(_pointer_type_cache, (PyObject *)Py_TYPE(arg));
+       if (typ)
+               return PyObject_CallFunctionObjArgs(typ, arg, NULL);
+       typ = POINTER(NULL, (PyObject *)Py_TYPE(arg));
+       if (typ == NULL)
+                       return NULL;
+       result = PyObject_CallFunctionObjArgs(typ, arg, NULL);
+       Py_DECREF(typ);
+       return result;
+}
+
 PyMethodDef module_methods[] = {
+       {"POINTER", POINTER, METH_O },
+       {"pointer", pointer, METH_O },
        {"_unpickle", unpickle, METH_VARARGS },
        {"resize", resize, METH_VARARGS, "Resize the memory buffer of a ctypes instance"},
 #ifdef CTYPES_UNICODE
index d0e781421cf628a8dbd42da4b0f232abfc7e05a0..8f6846a4476f2b6f75b59ed81ba36a2100d67d85 100644 (file)
@@ -415,6 +415,7 @@ extern PyObject *CData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t in
 /* XXX better name needed! */
 extern int IsSimpleSubType(PyObject *obj);
 
+extern PyObject *_pointer_type_cache;
 
 #ifdef MS_WIN32
 extern PyObject *ComError;