[ctypes-commit] ctypes/source _ctypes.c,1.163,1.164
Brought to you by:
theller
From: Thomas H. <th...@us...> - 2004-10-08 20:17:03
|
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30719 Modified Files: _ctypes.c Log Message: ctypes _pointer_type_cache now lives in the _ctypes module, to make it available to C code. Setting the _fields_ attribute on a Structure or Union type after creation automatically update the POINTER instance to it when it already exists, this allows to use POINTER(<type>) in the _fields_ list without need to update the POINTER type later. Implemented a customg from_param class method for CFuncPtrType: Python callables can now be passed directly as arguments to functions requiring callbacks: WINFUNCTYPE() or CFUNCTYPE() in the argtypes list. To avoid having to keep a reference to the created callback function explicitely (which will always be forgotten), started code to keep a reference automatically - currently this only works for functions, *not* for methods!!! Index: _ctypes.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/_ctypes.c,v retrieving revision 1.163 retrieving revision 1.164 diff -C2 -d -r1.163 -r1.164 *** _ctypes.c 28 Sep 2004 14:00:18 -0000 1.163 --- _ctypes.c 8 Oct 2004 20:16:28 -0000 1.164 *************** *** 98,101 **** --- 98,102 ---- PyObject *PyExc_ArgError; + static PyObject *PointerType_cache; char *conversion_mode_encoding = NULL; *************** *** 134,138 **** if (fields == NULL) { PyErr_Clear(); ! return result; } dict = StgDict_FromDict(fields, cls_dict, isStruct); --- 135,139 ---- if (fields == NULL) { PyErr_Clear(); ! return (PyObject *)result; } dict = StgDict_FromDict(fields, cls_dict, isStruct); *************** *** 306,309 **** --- 307,327 ---- }; + staticforward PyObject * + PointerType_set_type(PyTypeObject *, PyObject *); + + /* If the _fields_ attribute has been set on a Structure or Union type, + * we must update the Pointer's type if there is already one. + */ + static int + StructUnion_UpdatePointer_Type(PyObject *self) + { + PyObject *ptr = PyDict_GetItem(PointerType_cache, self); + if (ptr + && PyType_Check(ptr) + && (NULL == PointerType_set_type((PyTypeObject *)ptr, self))) + return -1; + return 0; + } + static int StructUnionType_setattro(PyTypeObject *self, PyObject *name, PyObject *value, *************** *** 330,333 **** --- 348,353 ---- Py_DECREF(self->tp_dict); self->tp_dict = dict; + if (-1 == StructUnion_UpdatePointer_Type((PyObject *)self)) + return -1; } if (PyString_Check(name) *************** *** 460,463 **** --- 480,486 ---- PointerType_SetProto(StgDictObject *stgdict, PyObject *proto) { + /* XXX makes no sense to check for proto != NULL, + * and later call Py_INCREF on it. + */ if (proto && !PyType_Check(proto)) { PyErr_SetString(PyExc_TypeError, *************** *** 500,508 **** proto = PyDict_GetItemString(typedict, "_type_"); /* Borrowed ref */ ! if (proto && -1 == PointerType_SetProto(stgdict, proto)) { ! Py_DECREF((PyObject *)stgdict); ! return NULL; } - /* create the new instance (which is a class, since we are a metatype!) */ --- 523,532 ---- proto = PyDict_GetItemString(typedict, "_type_"); /* Borrowed ref */ ! if (proto && PyType_stgdict(proto)) { ! if (-1 == PointerType_SetProto(stgdict, proto)) { ! Py_DECREF((PyObject *)stgdict); ! return NULL; ! } } /* create the new instance (which is a class, since we are a metatype!) */ *************** *** 510,515 **** if (result == NULL) return NULL; ! ! /* replace the class dict by our updated spam dict */ if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { Py_DECREF(result); --- 534,538 ---- if (result == NULL) return NULL; ! /* replace the class dict by our updated StgDict */ if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { Py_DECREF(result); *************** *** 519,523 **** Py_DECREF(result->tp_dict); result->tp_dict = (PyObject *)stgdict; - return (PyObject *)result; } --- 542,545 ---- *************** *** 528,531 **** --- 550,554 ---- { StgDictObject *dict; + PyObject *old_type; dict = PyType_stgdict((PyObject *)self); *************** *** 535,538 **** --- 558,567 ---- return NULL; + old_type = PyDict_GetItemString((PyObject *)dict, "_type_"); + if (old_type && old_type != type) { + PyErr_SetString(PyExc_AttributeError, + "_type_ already set"); + return NULL; + } if (-1 == PyDict_SetItemString((PyObject *)dict, "_type_", type)) return NULL; *************** *** 559,566 **** } } if (PointerObject_Check(value)) { StgDictObject *v = PyObject_stgdict(value); StgDictObject *t = PyType_stgdict(type); ! if (PyObject_IsSubclass(v->proto, t->proto)) { Py_INCREF(value); return value; --- 588,601 ---- } } + if (PyObject_IsInstance(value, type)) { + Py_INCREF(value); + return value; + } if (PointerObject_Check(value)) { StgDictObject *v = PyObject_stgdict(value); StgDictObject *t = PyType_stgdict(type); ! if (v && v->proto ! && t && t->proto ! && PyObject_IsSubclass(v->proto, t->proto)) { Py_INCREF(value); return value; *************** *** 1290,1294 **** PyCArgObject *parg; struct fielddesc *fd; - /* If the value is already an instance of the requested type, we can use it as is */ --- 1325,1328 ---- *************** *** 1513,1516 **** --- 1547,1608 ---- } + static PyObject * + CFuncPtrType_from_param(PyObject *type, PyObject *value) + { + if (1 == PyObject_IsInstance(value, type)) { + Py_INCREF(value); + return value; + } + /* normal python object, maybe a function, maybe another callable. We + * create an object of the required type automatically, but we have to + * keep a reference to it alive as long as the callback is used. We + * do not know how long it is used, but we assume that the lifetime of + * the callable is suffifient. This works for normal functions (where + * we attach it as _callback_ attribute to the function), but not for + * bound methods. + * + * For bound methods, we should keep the callback alive as long as the + * instance is alive, but we do not want to insret something into the + * instance's __dict__. + * Can we use a weak ref to the instance? XXX Later. + */ + if (0 == PyObject_IsInstance(value, (PyObject *)&CFuncPtr_Type)) { + PyObject *result = PyObject_CallFunctionObjArgs(type, value, NULL); + if (result == NULL) + return NULL; + if (-1 == PyObject_SetAttrString(value, "_callback_", result)) { + PyErr_Clear(); + } + return result; + } + /* Not sure this one is possible. byref() of a FUNCTYPE? */ + if (PyCArg_CheckExact(value)) { + PyCArgObject *p = (PyCArgObject *)value; + PyObject *ob = p->obj; + StgDictObject *dict; + dict = PyType_stgdict(type); + + /* If we got a PyCArgObject, we must check if the object packed in it + is an instance of the type's dict->proto */ + if(dict && ob + && PyObject_IsInstance(ob, dict->proto)) { + Py_INCREF(value); + return value; + } + } + PyErr_Format(PyExc_TypeError, + "expected %s instance instead of %s", + ((PyTypeObject *)type)->tp_name, + value->ob_type->tp_name); + return NULL; + } + + static PyMethodDef CFuncPtrType_methods[] = { + { "from_param", CFuncPtrType_from_param, METH_O, from_param_doc }, + { "from_address", CDataType_from_address, METH_O, from_address_doc }, + { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc }, + { NULL, NULL }, + }; + PyTypeObject CFuncPtrType_Type = { PyObject_HEAD_INIT(NULL) *************** *** 1542,1546 **** 0, /* tp_iter */ 0, /* tp_iternext */ ! CDataType_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ --- 1634,1638 ---- 0, /* tp_iter */ 0, /* tp_iternext */ ! CFuncPtrType_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ *************** *** 3283,3287 **** return -1; } - stgdict = PyObject_stgdict((PyObject *)self); if (index != 0) { --- 3375,3378 ---- *************** *** 3291,3295 **** } size = stgdict->size / stgdict->length; ! return CData_set((PyObject *)self, stgdict->proto, stgdict->setfunc, value, index, size, *(void **)self->b_ptr); --- 3382,3389 ---- } size = stgdict->size / stgdict->length; ! /* Later... ! return Pointer_set((PyObject *)self, stgdict->proto, stgdict->setfunc, value, ! index, size, self->b_ptr); ! */ return CData_set((PyObject *)self, stgdict->proto, stgdict->setfunc, value, index, size, *(void **)self->b_ptr); *************** *** 3749,3752 **** --- 3843,3849 ---- PyModule_AddObject(m, "FUNCFLAG_CDECL", PyInt_FromLong(FUNCFLAG_CDECL)); PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyInt_FromLong(FUNCFLAG_PYTHONAPI)); + PointerType_cache = PyDict_New(); + Py_INCREF(PointerType_cache); + PyModule_AddObject(m, "_pointer_type_cache", PointerType_cache); PyModule_AddStringConstant(m, "__version__", "0.9.2"); |