root/releases/pkgcore/0.2.2/src/caching.c @ marienz%2540gentoo.org-20061129021619-h92kexkktibvv60m

Revision marienz%2540gentoo.org-20061129021619-h92kexkktibvv60m, 24.6 KB (checked in by Marien Zwart <marienz@…>, 2 years ago)

Improve error handling in cpython module initialization.

Line 
1/*
2 * Copyright: 2006 Brian Harring <ferringb@gmail.com>
3 * Copyright: 2006 Marien Zwart <marienz@gentoo.org>
4 * License: GPL2
5 *
6 * C version of some of pkgcore (for extra speed).
7 */
8
9/* This does not really do anything since we do not use the "#"
10 * specifier in a PyArg_Parse or similar call, but hey, not using it
11 * means we are Py_ssize_t-clean too!
12 */
13
14#define PY_SSIZE_T_CLEAN
15
16#include <Python.h>
17#include "py24-compatibility.h"
18
19static PyObject *pkgcore_caching_disable_str = NULL;
20
21/*
22 * WeakValFinalizer: holds a reference to a dict and key,
23 * does "del dict[key]" when called. Used as weakref callback.
24 * Only used internally (does not expose a constructor/new method).
25 *
26 * Together with a "normal" PyDict this is used as a much more minimal
27 * version of python's weakref.WeakValueDictionary. One noticable
28 * difference between that and this is that WeakValueDictionary gives
29 * the weakref callbacks responsible for removing an item from the
30 * dict a weakref to the dict, while we use a "hard" reference to it.
31 *
32 * WeakValueDictionary has to do it that way to prevent objects in the
33 * dict from keeping the dict alive. That should not be an issue here:
34 * the objects in the dict have a hard reference to the dict through
35 * their type anyway. So this simplifies things a bit (especially
36 * since you cannot weakref a PyDict, it would have to be subclassed
37 * to add that ability (WeakValueDictionary is a UserDict, not a
38 * "real" dict, so it does not have that problem)).
39 */
40
41typedef struct {
42    PyObject_HEAD
43    PyObject *dict;
44    PyObject *key;
45} pkgcore_WeakValFinalizer;
46
47static void
48pkgcore_WeakValFinalizer_dealloc(pkgcore_WeakValFinalizer *self)
49{
50    Py_CLEAR(self->dict);
51    Py_CLEAR(self->key);
52    self->ob_type->tp_free((PyObject*) self);
53}
54
55static PyObject *
56pkgcore_WeakValFinalizer_call(pkgcore_WeakValFinalizer *self,
57    PyObject *args, PyObject *kwargs)
58{
59    /* We completely ignore whatever arguments are passed to us
60       (should be a single positional (the weakref) we do not need). */
61    if (PyDict_DelItem(self->dict, self->key) < 0)
62        return NULL;
63    Py_RETURN_NONE;
64}
65
66static int
67pkgcore_WeakValFinalizer_traverse(
68    pkgcore_WeakValFinalizer *self, visitproc visit, void *arg)
69{
70    Py_VISIT(self->dict);
71    Py_VISIT(self->key);
72    return 0;
73}
74
75static int
76pkgcore_WeakValFinalizer_heapyrelate(NyHeapRelate *r)
77{
78    pkgcore_WeakValFinalizer *v = (pkgcore_WeakValFinalizer*)r->src;
79    INTERATTR(dict);
80    INTERATTR(key);
81    return 0;
82}
83
84static PyTypeObject pkgcore_WeakValFinalizerType = {
85    PyObject_HEAD_INIT(NULL)
86    0,                                               /* ob_size */
87    "pkgcore.util._caching.WeakValFinalizer",        /* tp_name */
88    sizeof(pkgcore_WeakValFinalizer),                /* tp_basicsize */
89    0,                                               /* tp_itemsize */
90    (destructor)pkgcore_WeakValFinalizer_dealloc,    /* tp_dealloc */
91    0,                                               /* tp_print */
92    0,                                               /* tp_getattr */
93    0,                                               /* tp_setattr */
94    0,                                               /* tp_compare */
95    0,                                               /* tp_repr */
96    0,                                               /* tp_as_number */
97    0,                                               /* tp_as_sequence */
98    0,                                               /* tp_as_mapping */
99    0,                                               /* tp_hash  */
100    (ternaryfunc)pkgcore_WeakValFinalizer_call,      /* tp_call */
101    (reprfunc)0,                                     /* tp_str */
102    0,                                               /* tp_getattro */
103    0,                                               /* tp_setattro */
104    0,                                               /* tp_as_buffer */
105    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,         /* tp_flags */
106    "WeakValFinalizer objects",                      /* tp_doc */
107    (traverseproc)pkgcore_WeakValFinalizer_traverse, /* tp_traverse */
108};
109
110static pkgcore_WeakValFinalizer *
111pkgcore_WeakValFinalizer_create(PyObject *dict, PyObject *key)
112{
113    pkgcore_WeakValFinalizer *finalizer = PyObject_GC_New(
114        pkgcore_WeakValFinalizer, &pkgcore_WeakValFinalizerType);
115
116    if (NULL == finalizer)
117        return NULL;
118
119    Py_INCREF(dict);
120    finalizer->dict = dict;
121    Py_INCREF(key);
122    finalizer->key = key;
123
124    PyObject_GC_Track(finalizer);
125
126    return finalizer;
127}
128
129typedef struct {
130    PyObject_HEAD
131    PyObject *dict;
132} pkgcore_WeakValCache;
133
134static PyObject *
135pkgcore_WeakValCache_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
136{
137    pkgcore_WeakValCache *self;
138    self = (pkgcore_WeakValCache *)type->tp_alloc(type, 0);
139    if(!self)
140        return (PyObject *)NULL;
141    self->dict = PyDict_New();
142    if(!self->dict) {
143        Py_DECREF(self);
144        return NULL;
145    }
146    return (PyObject *)self;
147}
148
149static int
150pkgcore_WeakValCache_traverse(
151    pkgcore_WeakValCache *self, visitproc visit, void *arg)
152{
153    Py_VISIT(self->dict);
154    return 0;
155}
156
157static int
158pkgcore_WeakValCache_heapyrelate(NyHeapRelate *r)
159{
160    pkgcore_WeakValCache *v = (pkgcore_WeakValCache*) r->src;
161    INTERATTR(dict);
162    return 0;
163}
164
165static int
166pkgcore_WeakValCache_clear(pkgcore_WeakValCache *self)
167{
168    /* TODO someone who understands python gc should check if the
169     * following logic makes sense. --marienz
170     *
171     * We could simply Py_CLEAR(self->dict) here but since we must be
172     * in a mostly sane state (at least not segfault) after _clear
173     * that would mean a lot of extra NULL checks in our methods.
174     * Since we only need to clear references that "may have created
175     * cycles" and we should have the only reference to self->dict
176     * ourself just clearing the dict contents should suffice.
177     */
178    PyDict_Clear(self->dict);
179    return 0;
180}
181
182static PyObject *
183pkgcore_WeakValCache_clear_method(pkgcore_WeakValCache *self)
184{
185    pkgcore_WeakValCache_clear(self);
186    Py_RETURN_NONE;
187}
188
189static void
190pkgcore_WeakValCache_dealloc(pkgcore_WeakValCache *self)
191{
192    Py_CLEAR(self->dict);
193    self->ob_type->tp_free((PyObject *)self);
194}
195
196static Py_ssize_t
197pkgcore_WeakValCache_len(pkgcore_WeakValCache *self)
198{
199    return PyDict_Size(self->dict);
200}
201
202static int
203pkgcore_WeakValCache_setitem(pkgcore_WeakValCache *self, PyObject *key,
204    PyObject *val)
205{
206    if(NULL == val) {
207        return PyDict_SetItem(self->dict, (PyObject*)key, (PyObject*)val);
208    }
209    if(PyWeakref_Check(val)) {
210        PyErr_SetString(PyExc_TypeError, "cannot set value to a weakref");
211        return -1;
212    }
213
214    pkgcore_WeakValFinalizer *finalizer = pkgcore_WeakValFinalizer_create(
215        self->dict, key);
216    if (!finalizer)
217        return -1;
218
219    PyObject *weakref = PyWeakref_NewRef(val, (PyObject*)finalizer);
220    Py_DECREF(finalizer);
221    int ret = -1;
222    if (weakref) {
223        ret = PyDict_SetItem(self->dict, key, (PyObject*)weakref);
224        Py_DECREF(weakref);
225    }
226    return ret;
227}
228
229PyObject *
230pkgcore_WeakValCache_getitem(pkgcore_WeakValCache *self, PyObject *key)
231{
232    PyObject *resobj, *actual = NULL;
233    resobj = PyDict_GetItem(self->dict, key);
234    if(resobj) {
235        actual = PyWeakref_GetObject(resobj);
236        if (actual == Py_None) {
237            // PyWeakref_GetObject returns a borrowed reference, do not
238            // clear it
239            actual = NULL;
240            /* wipe the weakref err */
241            PyErr_Clear();
242            PyDict_DelItem(self->dict, key);
243            if(!PyErr_Occurred()) {
244                PyErr_SetObject(PyExc_KeyError, key);
245            }
246        } else {
247            Py_INCREF(actual);
248        }
249    } else {
250        PyErr_SetObject(PyExc_KeyError, key);
251    }
252    return actual;
253}
254
255static PyObject *
256pkgcore_WeakValCache_get(pkgcore_WeakValCache *self, PyObject *args)
257{
258    Py_ssize_t size = PyTuple_Size(args);
259    if(size == -1)
260        return NULL;
261    PyObject *key, *resobj;
262    if(size < 1 || size > 2) {
263        PyErr_SetString(PyExc_TypeError,
264            "get requires one arg (key), with optional default to return");
265        return (PyObject *)NULL;
266    }
267    key = PyTuple_GET_ITEM(args, 0);
268    if(!key) {
269        assert(PyErr_Occurred());
270        return (PyObject *)NULL;
271    }
272   
273    PyErr_Clear();
274    resobj = PyObject_GetItem((PyObject *)self, key);
275    if(resobj) {
276        assert(!PyErr_Occurred());
277        return resobj;
278
279    } else if(PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_KeyError)) {
280        // if the error wasn't that the key isn't found, return
281        return resobj;
282    }
283
284    PyErr_Clear();
285    if(size == 2) {
286        resobj = PyTuple_GET_ITEM(args, 1);
287    } else {
288        resobj = Py_None;
289    }
290    Py_INCREF(resobj);
291    return resobj;
292}
293
294static PyMappingMethods pkgcore_WeakValCache_as_mapping = {
295    (lenfunc)pkgcore_WeakValCache_len,               /* len() */
296    (binaryfunc)pkgcore_WeakValCache_getitem,        /* getitem */
297    (objobjargproc)pkgcore_WeakValCache_setitem,     /* setitem */
298};             
299
300
301static PyMethodDef pkgcore_WeakValCache_methods[] = {
302    {"get", (PyCFunction)pkgcore_WeakValCache_get, METH_VARARGS,
303        "get(key, default=None)"},
304    {"clear", (PyCFunction)pkgcore_WeakValCache_clear_method, METH_NOARGS,
305        "clear()"},
306    {NULL}
307};
308
309/* WeakValCache; simplified WeakValDictionary. */
310
311static PyTypeObject pkgcore_WeakValCacheType = {
312    PyObject_HEAD_INIT(NULL)
313    0,                                               /* ob_size */
314    "pkgcore.util._caching.WeakValCache",            /* tp_name */
315    sizeof(pkgcore_WeakValCache),                    /* tp_basicsize */
316    0,                                               /* tp_itemsize */
317    (destructor)pkgcore_WeakValCache_dealloc,        /* tp_dealloc */
318    0,                                               /* tp_print */
319    0,                                               /* tp_getattr */
320    0,                                               /* tp_setattr */
321    0,                                               /* tp_compare */
322    0,                                               /* tp_repr */
323    0,                                               /* tp_as_number */
324    0,                                               /* tp_as_sequence */
325    &pkgcore_WeakValCache_as_mapping,                /* tp_as_mapping */
326    0,                                               /* tp_hash  */
327    0,                                               /* tp_call */
328    (reprfunc)0,                                     /* tp_str */
329    0,                                               /* tp_getattro */
330    0,                                               /* tp_setattro */
331    0,                                               /* tp_as_buffer */
332    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,         /* tp_flags */
333    0,                                               /* tp_doc */
334    (traverseproc)pkgcore_WeakValCache_traverse,     /* tp_traverse */
335    (inquiry)pkgcore_WeakValCache_clear,             /* tp_clear */
336    0,                                               /* tp_richcompare */
337    0,                                               /* tp_weaklistoffset */
338    0,                                               /* tp_iter */
339    0,                                               /* tp_iternext */
340    pkgcore_WeakValCache_methods,                    /* tp_methods */
341    0,                                               /* tp_members */
342    0,                                               /* tp_getset */
343    0,                                               /* tp_base */
344    0,                                               /* tp_dict */
345    0,                                               /* tp_descr_get */
346    0,                                               /* tp_descr_set */
347    0,                                               /* tp_dictoffset */
348    0,                                               /* tp_init */
349    0,                                               /* tp_alloc */
350    pkgcore_WeakValCache_new,                        /* tp_new */
351};
352
353
354/* WeakInstMeta: metaclass for instance caching. */
355
356typedef struct {
357    PyHeapTypeObject type;
358    PyObject *inst_dict;
359    int inst_caching;
360} pkgcore_WeakInstMeta;
361
362static void
363pkgcore_WeakInstMeta_dealloc(pkgcore_WeakInstMeta* self)
364{
365    Py_CLEAR(self->inst_dict);
366    ((PyObject*)self)->ob_type->tp_free((PyObject *)self);
367}
368
369static PyTypeObject pkgcore_WeakInstMetaType;
370
371static PyObject *
372pkgcore_WeakInstMeta_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
373{
374    const char *name;
375    PyTupleObject *bases;
376    PyObject *d;
377    int inst_caching = 0;
378    static char *kwlist[] = {"name", "bases", "dict", 0};
379
380    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!", kwlist,
381                                     &name,
382                                     &PyTuple_Type, &bases,
383                                     &PyDict_Type, &d))
384        return NULL;
385
386    PyObject *cachesetting = PyMapping_GetItemString(d, "__inst_caching__");
387    if (cachesetting) {
388        inst_caching = PyObject_IsTrue(cachesetting);
389        Py_DECREF(cachesetting);
390        if (inst_caching < 0)
391            return NULL;
392    } else {
393        if (!PyErr_ExceptionMatches(PyExc_KeyError))
394            return NULL;
395        PyErr_Clear();
396    }
397    if (PyDict_SetItemString(d, "__inst_caching__",
398                                inst_caching ? Py_True : Py_False) < 0)
399        return NULL;
400
401    if (inst_caching) {
402        PyObject *slots = PyMapping_GetItemString(d, "__slots__");
403        if (slots) {
404            int has_weakref = 0;
405            PyObject *base;
406            int i, n = PyTuple_GET_SIZE(bases);
407            for (i = 0; i < n; i++) {
408                base = PyTuple_GET_ITEM(bases, i);
409                if (PyObject_HasAttrString(base, "__weakref__")) {
410                    has_weakref = 1;
411                    break;
412                }
413            }
414            if (!has_weakref) {
415                PyObject *slottuple = Py_BuildValue("(s)", "__weakref__");
416                if (!slottuple) {
417                    Py_DECREF(slots);
418                    return NULL;
419                }
420                PyObject *newslots = PySequence_Concat(slots, slottuple);
421                Py_DECREF(slottuple);
422                if (!newslots)
423                    return NULL;
424                if (PyDict_SetItemString(d, "__slots__", newslots) < 0) {
425                    Py_DECREF(newslots);
426                    Py_DECREF(slots);
427                    return NULL;
428                }
429                Py_DECREF(newslots);
430            }
431            Py_DECREF(slots);
432        } else {
433            if (!PyErr_ExceptionMatches(PyExc_KeyError))
434                return NULL;
435            PyErr_Clear();
436        }
437    }
438
439    pkgcore_WeakInstMeta *self;
440    self = (pkgcore_WeakInstMeta*)PyType_Type.tp_new(type, args, kwargs);
441    if (!self)
442        return NULL;
443
444    self->inst_caching = inst_caching;
445
446    if (inst_caching) {
447        if (!(self->inst_dict = PyDict_New())) {
448            Py_DECREF((PyObject*)self);
449            return NULL;
450        }
451    }
452    return (PyObject*) self;
453}
454
455
456static PyObject *
457pkgcore_WeakInstMeta_call(pkgcore_WeakInstMeta *self,
458    PyObject *args, PyObject *kwargs)
459{
460    PyObject *key, *kwlist, *kwtuple, *resobj = NULL;
461    int result;
462    if (!self->inst_caching)
463        /* No caching, just do what a "normal" type does */
464        return PyType_Type.tp_call((PyObject*)self, args, kwargs);
465
466    Py_ssize_t len = kwargs ? PyDict_Size(kwargs) : 0;
467    if (len) {
468        /* If disable_inst_caching=True is passed pop it and disable caching */
469        PyObject *obj = PyDict_GetItem(kwargs, pkgcore_caching_disable_str);
470        if (obj) {
471            result = PyObject_IsTrue(obj);
472            if (result < 0)
473                return NULL;
474
475            if (PyDict_DelItem(kwargs, pkgcore_caching_disable_str))
476                return NULL;
477
478            if (result)
479                return PyType_Type.tp_call((PyObject*)self, args, kwargs);
480        }
481        /* Convert kwargs to a sorted tuple so we can hash it. */
482        if (!(kwlist = PyDict_Items(kwargs)))
483            return NULL;
484
485        if (len > 1 && PyList_Sort(kwlist) < 0) {
486            Py_DECREF(kwlist);
487            return NULL;
488        }
489
490        kwtuple = PyList_AsTuple(kwlist);
491        Py_DECREF(kwlist);
492        if (!kwtuple)
493            return NULL;
494    } else {
495        /* null kwargs is equivalent to a zero-length tuple */
496        Py_INCREF(Py_None);
497        kwtuple = Py_None;
498    }
499
500    /* Construct the dict key. Be careful not to leak this below! */
501    key = PyTuple_Pack(2, args, kwtuple);
502    Py_DECREF(kwtuple);
503    if (!key)
504        return NULL;
505
506    // borrowed reference from PyDict_GetItem...
507    resobj = PyDict_GetItem(self->inst_dict, key);
508
509    if (resobj) {
510        /* We have a weakref cached, return the value if it is still there */
511        PyObject *actual = PyWeakref_GetObject(resobj);
512        if (!actual) {
513            Py_DECREF(key);
514            return NULL;
515        }
516        if (actual != Py_None) {
517            Py_INCREF(actual);
518            Py_DECREF(key);
519            return actual;
520        }
521        /* PyWeakref_GetObject returns a borrowed reference, do not clear it */
522    }
523    // if we got here, it's either not cached, or the key is unhashable.
524    // we catch the unhashable when we try to save the key.
525
526    resobj = PyType_Type.tp_call((PyObject*)self, args, kwargs);
527    if (!resobj) {
528        Py_DECREF(key);
529        return NULL;
530    }
531
532    pkgcore_WeakValFinalizer *finalizer = pkgcore_WeakValFinalizer_create(
533        self->inst_dict, key);
534    if (!finalizer) {
535        Py_DECREF(key);
536        Py_DECREF(resobj);
537        return NULL;
538    }
539
540    PyObject *weakref = PyWeakref_NewRef(resobj, (PyObject*)finalizer);
541    Py_DECREF(finalizer);
542    if (!weakref) {
543        Py_DECREF(key);
544        Py_DECREF(resobj);
545        return NULL;
546    }
547
548    result = PyDict_SetItem(self->inst_dict, key, weakref);
549    Py_DECREF(weakref);
550
551    if (result < 0) {
552        if (PyErr_ExceptionMatches(PyExc_TypeError) ||
553            PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
554            PyErr_Clear();
555            PyObject *format, *formatargs, *message;
556            if ((format = PyString_FromString(
557                     "caching for %s, key=%s is unhashable"))) {
558                if ((formatargs = PyTuple_Pack(2, self, key))) {
559                    if ((message = PyString_Format(format, formatargs))) {
560                        /* Leave resobj NULL if PyErr_Warn raises. */
561                        if (PyErr_Warn(
562                                PyExc_UserWarning,
563                                PyString_AsString(message))) {
564                            resobj = NULL;
565                        }
566                        Py_DECREF(message);
567                    }
568                    Py_DECREF(formatargs);
569                }
570                Py_DECREF(format);
571            }
572        } else {
573            // unexpected exception... let it go.
574            resobj = NULL;
575        }
576    }
577    Py_DECREF(key);
578    return resobj;
579}
580
581
582PyDoc_STRVAR(
583    pkgcore_WeakInstMetaType__doc__,
584    "metaclass for instance caching, resulting in reuse of unique instances.\n"
585    "few notes-\n"
586    "  - instances must be immutable (or effectively so). Since creating a\n"
587    "    new instance may return a preexisting instance, this requirement\n"
588    "    B{must} be honored.\n"
589    "  - due to the potential for mishap, each subclass of a caching class \n"
590    "    must assign __inst_caching__ = True to enable caching for the\n"
591    "    derivative.\n"
592    "  - conversely, __inst_caching__ = False does nothing (although it's\n"
593    "    useful as a sign of I{do not enable caching for this class}\n"
594    "  - instance caching can be disabled per instantiation via passing\n"
595    "    disabling_inst_caching=True into the class constructor.\n"
596    "\n"
597    "Being a metaclass, the voodoo used doesn't require modification of the\n"
598    "class itself.\n"
599    "\n"
600    "Examples of usage are the restriction modules\n"
601    "L{packages<pkgcore.restrictions.packages>} and\n"
602    "L{values<pkgcore.restrictions.values>}\n"
603    );
604
605static PyTypeObject pkgcore_WeakInstMetaType = {
606    PyObject_HEAD_INIT(NULL)
607    0,                                               /* ob_size */
608    "pkgcore.util._caching.WeakInstMeta",            /* tp_name */
609    sizeof(pkgcore_WeakInstMeta),                    /* tp_basicsize */
610    0,                                               /* tp_itemsize */
611    /* methods */
612    (destructor)pkgcore_WeakInstMeta_dealloc,        /* tp_dealloc */
613    (printfunc)0,                                    /* tp_print */
614    (getattrfunc)0,                                  /* tp_getattr */
615    (setattrfunc)0,                                  /* tp_setattr */
616    (cmpfunc)0,                                      /* tp_compare */
617    (reprfunc)0,                                     /* tp_repr */
618    0,                                               /* tp_as_number */
619    0,                                               /* tp_as_sequence */
620    0,                                               /* tp_as_mapping */
621    (hashfunc)0,                                     /* tp_hash */
622    (ternaryfunc)pkgcore_WeakInstMeta_call,          /* tp_call */
623    (reprfunc)0,                                     /* tp_str */
624    0,                                               /* tp_getattro */
625    0,                                               /* tp_setattro */
626    0,                                               /* tp_as_buffer */
627    Py_TPFLAGS_DEFAULT,                              /* tp_flags */
628    pkgcore_WeakInstMetaType__doc__,                 /* tp_doc */
629    (traverseproc)0,                                 /* tp_traverse */
630    (inquiry)0,                                      /* tp_clear */
631    (richcmpfunc)0,                                  /* tp_richcompare */
632    0,                                               /* tp_weaklistoffset */
633    (getiterfunc)0,                                  /* tp_iter */
634    (iternextfunc)0,                                 /* tp_iternext */
635    0,                                               /* tp_methods */
636    0,                                               /* tp_members */
637    0,                                               /* tp_getset */
638    0, /* set to &PyType_Type later */               /* tp_base */
639    0,                                               /* tp_dict */
640    0,                                               /* tp_descr_get */
641    0,                                               /* tp_descr_set */
642    0,                                               /* tp_dictoffset */
643    (initproc)0,                                     /* tp_init */
644    0,                                               /* tp_alloc */
645    pkgcore_WeakInstMeta_new,                        /* tp_new */
646};
647
648
649static NyHeapDef pkgcore_caching_heapdefs[] = {
650    {
651        0,                            /* flags */
652        &pkgcore_WeakValFinalizerType, /* type */
653        0,                            /* size */
654        0,                            /* traverse */
655        pkgcore_WeakValFinalizer_heapyrelate /* relate */
656    },
657    {
658        0,                            /* flags */
659        &pkgcore_WeakValCacheType,    /* type */
660        0,                            /* size */
661        0,                            /* traverse */
662        pkgcore_WeakValCache_heapyrelate /* relate */
663    },
664    {0}
665};
666
667/* Module initialization */
668
669PyDoc_STRVAR(
670    pkgcore_module_documentation,
671    "C reimplementation of pkgcore.util.caching.");
672
673PyMODINIT_FUNC
674init_caching()
675{
676    /* Create the module and add the functions */
677    PyObject *m = Py_InitModule3(
678        "_caching", NULL, pkgcore_module_documentation);
679    if (!m)
680        return;
681
682    pkgcore_WeakInstMetaType.tp_base = &PyType_Type;
683
684    if (PyType_Ready(&pkgcore_WeakInstMetaType) < 0)
685        return;
686
687    if (PyType_Ready(&pkgcore_WeakValCacheType) < 0)
688        return;
689
690    if (PyType_Ready(&pkgcore_WeakValFinalizerType) < 0)
691        return;
692
693    if (!pkgcore_caching_disable_str) {
694        if (!(pkgcore_caching_disable_str =
695            PyString_FromString("disable_inst_caching")))
696            /* We can just return here, since the only way to get at
697             * this is through pkgcore_WeakInstMeta_call and that
698             * cannot be accessed yet.
699             */
700            return;
701    }
702
703    Py_INCREF(&pkgcore_WeakInstMetaType);
704    if (PyModule_AddObject(
705            m, "WeakInstMeta", (PyObject *)&pkgcore_WeakInstMetaType) == -1)
706        return;
707
708    Py_INCREF(&pkgcore_WeakValCacheType);
709    if (PyModule_AddObject(
710            m, "WeakValCache", (PyObject *)&pkgcore_WeakValCacheType) == -1)
711        return;
712
713    PyObject *cobject = PyCObject_FromVoidPtrAndDesc(
714        &pkgcore_caching_heapdefs, "NyHeapDef[] v1.0", 0);
715    if (!cobject)
716        return;
717
718    if (PyModule_AddObject(m, "_NyHeapDefs_", cobject) == -1)
719        return;
720
721    /* Success! */
722}
Note: See TracBrowser for help on using the browser.