Mercurial > cpython-lru_cache-weakref
view Objects/capsule.c @ 87690:66c1c9f32567 default tip
Add use_weakref option to functools.lru_cache
The use_weakref option makes lru_cache create weak references to the function
arguments when creating the cache key, which prevents them from staying in the
memory forever even after all other references to them are gone.
This is a proof of concept for http://bugs.python.org/issue19859
| author | Radomir Dopieralski <devel@sheep.art.pl> |
|---|---|
| date | Tue, 03 Dec 2013 16:02:48 +0100 |
| parents | 9108e7dcd7d8 |
| children |
line wrap: on
line source
/* Wrap void * pointers to be passed between C modules */ #include "Python.h" /* Internal structure of PyCapsule */ typedef struct { PyObject_HEAD void *pointer; const char *name; void *context; PyCapsule_Destructor destructor; } PyCapsule; static int _is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule) { if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) { PyErr_SetString(PyExc_ValueError, invalid_capsule); return 0; } return 1; } #define is_legal_capsule(capsule, name) \ (_is_legal_capsule(capsule, \ name " called with invalid PyCapsule object")) static int name_matches(const char *name1, const char *name2) { /* if either is NULL, */ if (!name1 || !name2) { /* they're only the same if they're both NULL. */ return name1 == name2; } return !strcmp(name1, name2); } PyObject * PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor) { PyCapsule *capsule; if (!pointer) { PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer"); return NULL; } capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type); if (capsule == NULL) { return NULL; } capsule->pointer = pointer; capsule->name = name; capsule->context = NULL; capsule->destructor = destructor; return (PyObject *)capsule; } int PyCapsule_IsValid(PyObject *o, const char *name) { PyCapsule *capsule = (PyCapsule *)o; return (capsule != NULL && PyCapsule_CheckExact(capsule) && capsule->pointer != NULL && name_matches(capsule->name, name)); } void * PyCapsule_GetPointer(PyObject *o, const char *name) { PyCapsule *capsule = (PyCapsule *)o; if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) { return NULL; } if (!name_matches(name, capsule->name)) { PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name"); return NULL; } return capsule->pointer; } const char * PyCapsule_GetName(PyObject *o) { PyCapsule *capsule = (PyCapsule *)o; if (!is_legal_capsule(capsule, "PyCapsule_GetName")) { return NULL; } return capsule->name; } PyCapsule_Destructor PyCapsule_GetDestructor(PyObject *o) { PyCapsule *capsule = (PyCapsule *)o; if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) { return NULL; } return capsule->destructor; } void * PyCapsule_GetContext(PyObject *o) { PyCapsule *capsule = (PyCapsule *)o; if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) { return NULL; } return capsule->context; } int PyCapsule_SetPointer(PyObject *o, void *pointer) { PyCapsule *capsule = (PyCapsule *)o; if (!pointer) { PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer"); return -1; } if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) { return -1; } capsule->pointer = pointer; return 0; } int PyCapsule_SetName(PyObject *o, const char *name) { PyCapsule *capsule = (PyCapsule *)o; if (!is_legal_capsule(capsule, "PyCapsule_SetName")) { return -1; } capsule->name = name; return 0; } int PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor) { PyCapsule *capsule = (PyCapsule *)o; if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) { return -1; } capsule->destructor = destructor; return 0; } int PyCapsule_SetContext(PyObject *o, void *context) { PyCapsule *capsule = (PyCapsule *)o; if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) { return -1; } capsule->context = context; return 0; } void * PyCapsule_Import(const char *name, int no_block) { PyObject *object = NULL; void *return_value = NULL; char *trace; size_t name_length = (strlen(name) + 1) * sizeof(char); char *name_dup = (char *)PyMem_MALLOC(name_length); if (!name_dup) { return NULL; } memcpy(name_dup, name, name_length); trace = name_dup; while (trace) { char *dot = strchr(trace, '.'); if (dot) { *dot++ = '\0'; } if (object == NULL) { if (no_block) { object = PyImport_ImportModuleNoBlock(trace); } else { object = PyImport_ImportModule(trace); if (!object) { PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace); } } } else { PyObject *object2 = PyObject_GetAttrString(object, trace); Py_DECREF(object); object = object2; } if (!object) { goto EXIT; } trace = dot; } /* compare attribute name to module.name by hand */ if (PyCapsule_IsValid(object, name)) { PyCapsule *capsule = (PyCapsule *)object; return_value = capsule->pointer; } else { PyErr_Format(PyExc_AttributeError, "PyCapsule_Import \"%s\" is not valid", name); } EXIT: Py_XDECREF(object); if (name_dup) { PyMem_FREE(name_dup); } return return_value; } static void capsule_dealloc(PyObject *o) { PyCapsule *capsule = (PyCapsule *)o; if (capsule->destructor) { capsule->destructor(o); } PyObject_DEL(o); } static PyObject * capsule_repr(PyObject *o) { PyCapsule *capsule = (PyCapsule *)o; const char *name; const char *quote; if (capsule->name) { quote = "\""; name = capsule->name; } else { quote = ""; name = "NULL"; } return PyUnicode_FromFormat("<capsule object %s%s%s at %p>", quote, name, quote, capsule); } PyDoc_STRVAR(PyCapsule_Type__doc__, "Capsule objects let you wrap a C \"void *\" pointer in a Python\n\ object. They're a way of passing data through the Python interpreter\n\ without creating your own custom type.\n\ \n\ Capsules are used for communication between extension modules.\n\ They provide a way for an extension module to export a C interface\n\ to other extension modules, so that extension modules can use the\n\ Python import mechanism to link to one another.\n\ "); PyTypeObject PyCapsule_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "PyCapsule", /*tp_name*/ sizeof(PyCapsule), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ capsule_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_reserved*/ capsule_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ 0, /*tp_flags*/ PyCapsule_Type__doc__ /*tp_doc*/ };
