Issue #2616: Implement ctypes.pointer() and ctypes.POINTER() in C for

better performance.
This commit is contained in:
Thomas Heller 2008-04-14 16:10:07 +00:00
parent da950eb01c
commit 046e6a43ff
5 changed files with 83 additions and 25 deletions

View 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

View File

@ -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.

View 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;

View 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

View 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;