root/masterdriverz/snakeoil/src/caching.c @ ferringb%2540gmail.com-20070327133451-49cwf0k0bobsjx7t

Revision ferringb%2540gmail.com-20070327133451-49cwf0k0bobsjx7t, 24.2 kB (checked in by Brian Harring <ferringb@…>, 22 months ago)

pull in cleanup/additions by Kyle McFarland?.

Line 
1/*
2 * Copyright: 2006-2007 Brian Harring <ferringb@gmail.com>
3 * Copyright: 2006 Marien Zwart <marienz@gentoo.org>
4 * License: GPL2
5 *
6 * C version of some of snakeoil (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 "snakeoil/py24-compatibility.h"
18
19static PyObject *snakeoil_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} snakeoil_WeakValFinalizer;
46
47static void
48snakeoil_WeakValFinalizer_dealloc(snakeoil_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 *
56snakeoil_WeakValFinalizer_call(snakeoil_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
67snakeoil_WeakValFinalizer_traverse(
68    snakeoil_WeakValFinalizer *self, visitproc visit, void *arg)
69{
70    Py_VISIT(self->dict);
71    Py_VISIT(self->key);
72    return 0;
73}
74
75static int
76snakeoil_WeakValFinalizer_heapyrelate(NyHeapRelate *r)
77{
78    snakeoil_WeakValFinalizer *v = (snakeoil_WeakValFinalizer*)r->src;
79    INTERATTR(dict);
80    INTERATTR(key);
81    return 0;
82}
83
84static PyTypeObject snakeoil_WeakValFinalizerType = {
85    PyObject_HEAD_INIT(NULL)
86    0,                                               /* ob_size */
87    "snakeoil._caching.WeakValFinalizer",            /* tp_name */
88    sizeof(snakeoil_WeakValFinalizer),                /* tp_basicsize */
89    0,                                               /* tp_itemsize */
90    (destructor)snakeoil_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)snakeoil_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)snakeoil_WeakValFinalizer_traverse, /* tp_traverse */
108};
109
110static snakeoil_WeakValFinalizer *
111snakeoil_WeakValFinalizer_create(PyObject *dict, PyObject *key)
112{
113    snakeoil_WeakValFinalizer *finalizer = PyObject_GC_New(
114        snakeoil_WeakValFinalizer, &snakeoil_WeakValFinalizerType);
115
116    if (!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} snakeoil_WeakValCache;
133
134static PyObject *
135snakeoil_WeakValCache_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
136{
137    snakeoil_WeakValCache *self;
138    self = (snakeoil_WeakValCache *)type->tp_alloc(type, 0);
139    if(!self)
140        return 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
150snakeoil_WeakValCache_traverse(
151    snakeoil_WeakValCache *self, visitproc visit, void *arg)
152{
153    Py_VISIT(self->dict);
154    return 0;
155}
156
157static int
158snakeoil_WeakValCache_heapyrelate(NyHeapRelate *r)
159{
160    snakeoil_WeakValCache *v = (snakeoil_WeakValCache*) r->src;
161    INTERATTR(dict);
162    return 0;
163}
164
165static int
166snakeoil_WeakValCache_clear(snakeoil_WeakValCache *self)
167{
168    PyDict_Clear(self->dict);
169    return 0;
170}
171
172static PyObject *
173snakeoil_WeakValCache_clear_method(snakeoil_WeakValCache *self)
174{
175    snakeoil_WeakValCache_clear(self);
176    Py_RETURN_NONE;
177}
178
179static void
180snakeoil_WeakValCache_dealloc(snakeoil_WeakValCache *self)
181{
182    Py_CLEAR(self->dict);
183    self->ob_type->tp_free((PyObject *)self);
184}
185
186static Py_ssize_t
187snakeoil_WeakValCache_len(snakeoil_WeakValCache *self)
188{
189    return PyDict_Size(self->dict);
190}
191
192static int
193snakeoil_WeakValCache_setitem(snakeoil_WeakValCache *self, PyObject *key,
194    PyObject *val)
195{
196    if(!val) {
197        return PyDict_SetItem(self->dict, (PyObject*)key, (PyObject*)val);
198    }
199    if(PyWeakref_Check(val)) {
200        PyErr_SetString(PyExc_TypeError, "cannot set value to a weakref");
201        return -1;
202    }
203
204    int ret = -1;
205    snakeoil_WeakValFinalizer *finalizer = snakeoil_WeakValFinalizer_create(
206        self->dict, key);
207    if (finalizer) {
208        PyObject *weakref = PyWeakref_NewRef(val, (PyObject*)finalizer);
209        Py_DECREF(finalizer);
210        if (weakref) {
211            ret = PyDict_SetItem(self->dict, key, (PyObject*)weakref);
212            Py_DECREF(weakref);
213        }
214    }
215    return ret;
216}
217
218PyObject *
219snakeoil_WeakValCache_getitem(snakeoil_WeakValCache *self, PyObject *key)
220{
221    PyObject *resobj, *actual = NULL;
222    resobj = PyDict_GetItem(self->dict, key);
223    if(resobj) {
224        actual = PyWeakref_GetObject(resobj);
225        if (actual == Py_None) {
226            // PyWeakref_GetObject returns a borrowed reference, do not
227            // clear it
228            actual = NULL;
229            /* wipe the weakref err */
230            PyErr_Clear();
231            PyDict_DelItem(self->dict, key);
232            if(!PyErr_Occurred()) {
233                PyErr_SetObject(PyExc_KeyError, key);
234            }
235        } else {
236            Py_INCREF(actual);
237        }
238    } else {
239        PyErr_SetObject(PyExc_KeyError, key);
240    }
241    return actual;
242}
243
244static PyObject *
245snakeoil_WeakValCache_get(snakeoil_WeakValCache *self, PyObject *args)
246{
247    Py_ssize_t size = PyTuple_Size(args);
248    if(-1 == size)
249        return NULL;
250    PyObject *key, *resobj;
251    if(size < 1 || size > 2) {
252        PyErr_SetString(PyExc_TypeError,
253            "get requires one arg (key), with optional default to return");
254        return NULL;
255    }
256    key = PyTuple_GET_ITEM(args, 0);
257    if(!key) {
258        assert(PyErr_Occurred());
259        return NULL;
260    }
261
262    PyErr_Clear();
263    resobj = PyObject_GetItem((PyObject *)self, key);
264    if(resobj) {
265        assert(!PyErr_Occurred());
266        return resobj;
267
268    } else if(PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_KeyError)) {
269        // if the error wasn't that the key isn't found, return
270        return resobj;
271    }
272
273    PyErr_Clear();
274    if(size == 2) {
275        resobj = PyTuple_GET_ITEM(args, 1);
276    } else {
277        resobj = Py_None;
278    }
279    Py_INCREF(resobj);
280    return resobj;
281}
282
283static PyMappingMethods snakeoil_WeakValCache_as_mapping = {
284    (lenfunc)snakeoil_WeakValCache_len,               /* len() */
285    (binaryfunc)snakeoil_WeakValCache_getitem,        /* getitem */
286    (objobjargproc)snakeoil_WeakValCache_setitem,     /* setitem */
287};
288
289
290static PyMethodDef snakeoil_WeakValCache_methods[] = {
291    {"get", (PyCFunction)snakeoil_WeakValCache_get, METH_VARARGS,
292        "get(key, default=None)"},
293    {"clear", (PyCFunction)snakeoil_WeakValCache_clear_method, METH_NOARGS,
294        "clear()"},
295    {NULL}
296};
297
298/* WeakValCache; simplified WeakValDictionary. */
299
300static PyTypeObject snakeoil_WeakValCacheType = {
301    PyObject_HEAD_INIT(NULL)
302    0,                                               /* ob_size */
303    "snakeoil._caching.WeakValCache",                /* tp_name */
304    sizeof(snakeoil_WeakValCache),                    /* tp_basicsize */
305    0,                                               /* tp_itemsize */
306    (destructor)snakeoil_WeakValCache_dealloc,        /* tp_dealloc */
307    0,                                               /* tp_print */
308    0,                                               /* tp_getattr */
309    0,                                               /* tp_setattr */
310    0,                                               /* tp_compare */
311    0,                                               /* tp_repr */
312    0,                                               /* tp_as_number */
313    0,                                               /* tp_as_sequence */
314    &snakeoil_WeakValCache_as_mapping,                /* tp_as_mapping */
315    0,                                               /* tp_hash  */
316    0,                                               /* tp_call */
317    (reprfunc)0,                                     /* tp_str */
318    0,                                               /* tp_getattro */
319    0,                                               /* tp_setattro */
320    0,                                               /* tp_as_buffer */
321    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,         /* tp_flags */
322    0,                                               /* tp_doc */
323    (traverseproc)snakeoil_WeakValCache_traverse,     /* tp_traverse */
324    (inquiry)snakeoil_WeakValCache_clear,             /* tp_clear */
325    0,                                               /* tp_richcompare */
326    0,                                               /* tp_weaklistoffset */
327    0,                                               /* tp_iter */
328    0,                                               /* tp_iternext */
329    snakeoil_WeakValCache_methods,                    /* tp_methods */
330    0,                                               /* tp_members */
331    0,                                               /* tp_getset */
332    0,                                               /* tp_base */
333    0,                                               /* tp_dict */
334    0,                                               /* tp_descr_get */
335    0,                                               /* tp_descr_set */
336    0,                                               /* tp_dictoffset */
337    0,                                               /* tp_init */
338    0,                                               /* tp_alloc */
339    snakeoil_WeakValCache_new,                        /* tp_new */
340};
341
342
343/* WeakInstMeta: metaclass for instance caching. */
344
345typedef struct {
346    PyHeapTypeObject type;
347    PyObject *inst_dict;
348    int inst_caching;
349} snakeoil_WeakInstMeta;
350
351static void
352snakeoil_WeakInstMeta_dealloc(snakeoil_WeakInstMeta* self)
353{
354    Py_CLEAR(self->inst_dict);
355    ((PyObject*)self)->ob_type->tp_free((PyObject *)self);
356}
357
358static PyTypeObject snakeoil_WeakInstMetaType;
359
360static PyObject *
361snakeoil_WeakInstMeta_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
362{
363    const char *name;
364    PyTupleObject *bases;
365    PyObject *d;
366    int inst_caching = 0;
367    static char *kwlist[] = {"name", "bases", "dict", 0};
368
369    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!", kwlist,
370                                     &name,
371                                     &PyTuple_Type, &bases,
372                                     &PyDict_Type, &d))
373        return NULL;
374
375    PyObject *cachesetting = PyMapping_GetItemString(d, "__inst_caching__");
376    if (cachesetting) {
377        inst_caching = PyObject_IsTrue(cachesetting);
378        Py_DECREF(cachesetting);
379        if (inst_caching < 0)
380            return NULL;
381    } else {
382        if (!PyErr_ExceptionMatches(PyExc_KeyError))
383            return NULL;
384        PyErr_Clear();
385    }
386    if (PyDict_SetItemString(d, "__inst_caching__",
387                                inst_caching ? Py_True : Py_False) < 0)
388        return NULL;
389
390    if (inst_caching) {
391        PyObject *slots = PyMapping_GetItemString(d, "__slots__");
392        if (slots) {
393            int has_weakref = 0;
394            PyObject *base;
395            int i, n = PyTuple_GET_SIZE(bases);
396            for (i = 0; i < n; i++) {
397                base = PyTuple_GET_ITEM(bases, i);
398                if (PyObject_HasAttrString(base, "__weakref__")) {
399                    has_weakref = 1;
400                    break;
401                }
402            }
403            if (!has_weakref) {
404                PyObject *slottuple = Py_BuildValue("(s)", "__weakref__");
405                if (!slottuple) {
406                    Py_DECREF(slots);
407                    return NULL;
408                }
409                PyObject *newslots = PySequence_Concat(slots, slottuple);
410                Py_DECREF(slottuple);
411                if (!newslots)
412                    return NULL;
413                if (PyDict_SetItemString(d, "__slots__", newslots) < 0) {
414                    Py_DECREF(newslots);
415                    Py_DECREF(slots);
416                    return NULL;
417                }
418                Py_DECREF(newslots);
419            }
420            Py_DECREF(slots);
421        } else {
422            if (!PyErr_ExceptionMatches(PyExc_KeyError))
423                return NULL;
424            PyErr_Clear();
425        }
426    }
427
428    snakeoil_WeakInstMeta *self;
429    self = (snakeoil_WeakInstMeta*)PyType_Type.tp_new(type, args, kwargs);
430    if (!self)
431        return NULL;
432
433    self->inst_caching = inst_caching;
434
435    if (inst_caching) {
436        if (!(self->inst_dict = PyDict_New())) {
437            Py_DECREF((PyObject*)self);
438            return NULL;
439        }
440    }
441    return (PyObject*) self;
442}
443
444
445static PyObject *
446snakeoil_WeakInstMeta_call(snakeoil_WeakInstMeta *self,
447    PyObject *args, PyObject *kwargs)
448{
449    PyObject *key, *kwlist, *kwtuple, *resobj = NULL;
450    int result;
451    if (!self->inst_caching)
452        /* No caching, just do what a "normal" type does */
453        return PyType_Type.tp_call((PyObject*)self, args, kwargs);
454
455    Py_ssize_t len = kwargs ? PyDict_Size(kwargs) : 0;
456    if (len) {
457        /* If disable_inst_caching=True is passed pop it and disable caching */
458        PyObject *obj = PyDict_GetItem(kwargs, snakeoil_caching_disable_str);
459        if (obj) {
460            result = PyObject_IsTrue(obj);
461            if (result < 0)
462                return NULL;
463
464            if (PyDict_DelItem(kwargs, snakeoil_caching_disable_str))
465                return NULL;
466
467            if (result)
468                return PyType_Type.tp_call((PyObject*)self, args, kwargs);
469        }
470        /* Convert kwargs to a sorted tuple so we can hash it. */
471        if (!(kwlist = PyDict_Items(kwargs)))
472            return NULL;
473
474        if (len > 1 && PyList_Sort(kwlist) < 0) {
475            Py_DECREF(kwlist);
476            return NULL;
477        }
478
479        kwtuple = PyList_AsTuple(kwlist);
480        Py_DECREF(kwlist);
481        if (!kwtuple)
482            return NULL;
483    } else {
484        /* null kwargs is equivalent to a zero-length tuple */
485        Py_INCREF(Py_None);
486        kwtuple = Py_None;
487    }
488
489    /* Construct the dict key. Be careful not to leak this below! */
490    key = PyTuple_Pack(2, args, kwtuple);
491    Py_DECREF(kwtuple);
492    if (!key)
493        return NULL;
494
495    // borrowed reference from PyDict_GetItem...
496    resobj = PyDict_GetItem(self->inst_dict, key);
497
498    if (resobj) {
499        /* We have a weakref cached, return the value if it is still there */
500        PyObject *actual = PyWeakref_GetObject(resobj);
501        if (!actual) {
502            Py_DECREF(key);
503            return NULL;
504        }
505        if (actual != Py_None) {
506            Py_INCREF(actual);
507            Py_DECREF(key);
508            return actual;
509        }
510        /* PyWeakref_GetObject returns a borrowed reference, do not clear it */
511    }
512    // if we got here, it's either not cached, or the key is unhashable.
513    // we catch the unhashable when we try to save the key.
514
515    resobj = PyType_Type.tp_call((PyObject*)self, args, kwargs);
516    if (!resobj) {
517        Py_DECREF(key);
518        return NULL;
519    }
520
521    snakeoil_WeakValFinalizer *finalizer = snakeoil_WeakValFinalizer_create(
522        self->inst_dict, key);
523    if (!finalizer) {
524        Py_DECREF(key);
525        Py_DECREF(resobj);
526        return NULL;
527    }
528
529    PyObject *weakref = PyWeakref_NewRef(resobj, (PyObject*)finalizer);
530    Py_DECREF(finalizer);
531    if (!weakref) {
532        Py_DECREF(key);
533        Py_DECREF(resobj);
534        return NULL;
535    }
536
537    result = PyDict_SetItem(self->inst_dict, key, weakref);
538    Py_DECREF(weakref);
539
540    if (result < 0) {
541        if (PyErr_ExceptionMatches(PyExc_TypeError) ||
542            PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
543            PyErr_Clear();
544            PyObject *format, *formatargs, *message;
545            if ((format = PyString_FromString(
546                     "caching for %s, key=%s is unhashable"))) {
547                if ((formatargs = PyTuple_Pack(2, self, key))) {
548                    if ((message = PyString_Format(format, formatargs))) {
549                        /* Leave resobj NULL if PyErr_Warn raises. */
550                        if (PyErr_Warn(
551                                PyExc_UserWarning,
552                                PyString_AsString(message))) {
553                            resobj = NULL;
554                        }
555                        Py_DECREF(message);
556                    }
557                    Py_DECREF(formatargs);
558                }
559                Py_DECREF(format);
560            }
561        } else {
562            // unexpected exception... let it go.
563            resobj = NULL;
564        }
565    }
566    Py_DECREF(key);
567    return resobj;
568}
569
570
571PyDoc_STRVAR(
572    snakeoil_WeakInstMetaType__doc__,
573    "metaclass for instance caching, resulting in reuse of unique instances.\n"
574    "few notes-\n"
575    "  - instances must be immutable (or effectively so). Since creating a\n"
576    "    new instance may return a preexisting instance, this requirement\n"
577    "    B{must} be honored.\n"
578    "  - due to the potential for mishap, each subclass of a caching class \n"
579    "    must assign __inst_caching__ = True to enable caching for the\n"
580    "    derivative.\n"
581    "  - conversely, __inst_caching__ = False does nothing (although it's\n"
582    "    useful as a sign of I{do not enable caching for this class}\n"
583    "  - instance caching can be disabled per instantiation via passing\n"
584    "    disabling_inst_caching=True into the class constructor.\n"
585    "\n"
586    "Being a metaclass, the voodoo used doesn't require modification of the\n"
587    "class itself.\n"
588    "\n"
589    "Examples of usage are the restriction modules\n"
590    "L{packages<snakeoil.restrictions.packages>} and\n"
591    "L{values<snakeoil.restrictions.values>}\n"
592    );
593
594static PyTypeObject snakeoil_WeakInstMetaType = {
595    PyObject_HEAD_INIT(NULL)
596    0,                                               /* ob_size */
597    "snakeoil._caching.WeakInstMeta",            /* tp_name */
598    sizeof(snakeoil_WeakInstMeta),                    /* tp_basicsize */
599    0,                                               /* tp_itemsize */
600    /* methods */
601    (destructor)snakeoil_WeakInstMeta_dealloc,        /* tp_dealloc */
602    (printfunc)0,                                    /* tp_print */
603    (getattrfunc)0,                                  /* tp_getattr */
604    (setattrfunc)0,                                  /* tp_setattr */
605    (cmpfunc)0,                                      /* tp_compare */
606    (reprfunc)0,                                     /* tp_repr */
607    0,                                               /* tp_as_number */
608    0,                                               /* tp_as_sequence */
609    0,                                               /* tp_as_mapping */
610    (hashfunc)0,                                     /* tp_hash */
611    (ternaryfunc)snakeoil_WeakInstMeta_call,          /* tp_call */
612    (reprfunc)0,                                     /* tp_str */
613    0,                                               /* tp_getattro */
614    0,                                               /* tp_setattro */
615    0,                                               /* tp_as_buffer */
616    Py_TPFLAGS_DEFAULT,                              /* tp_flags */
617    snakeoil_WeakInstMetaType__doc__,                 /* tp_doc */
618    (traverseproc)0,                                 /* tp_traverse */
619    (inquiry)0,                                      /* tp_clear */
620    (richcmpfunc)0,                                  /* tp_richcompare */
621    0,                                               /* tp_weaklistoffset */
622    (getiterfunc)0,                                  /* tp_iter */
623    (iternextfunc)0,                                 /* tp_iternext */
624    0,                                               /* tp_methods */
625    0,                                               /* tp_members */
626    0,                                               /* tp_getset */
627    0, /* set to &PyType_Type later */               /* tp_base */
628    0,                                               /* tp_dict */
629    0,                                               /* tp_descr_get */
630    0,                                               /* tp_descr_set */
631    0,                                               /* tp_dictoffset */
632    (initproc)0,                                     /* tp_init */
633    0,                                               /* tp_alloc */
634    snakeoil_WeakInstMeta_new,                        /* tp_new */
635};
636
637
638static NyHeapDef snakeoil_caching_heapdefs[] = {
639    {
640        0,                            /* flags */
641        &snakeoil_WeakValFinalizerType, /* type */
642        0,                            /* size */
643        0,                            /* traverse */
644        snakeoil_WeakValFinalizer_heapyrelate /* relate */
645    },
646    {
647        0,                            /* flags */
648        &snakeoil_WeakValCacheType,    /* type */
649        0,                            /* size */
650        0,                            /* traverse */
651        snakeoil_WeakValCache_heapyrelate /* relate */
652    },
653    {0}
654};
655
656/* Module initialization */
657
658PyDoc_STRVAR(
659    snakeoil_module_documentation,
660    "C reimplementation of snakeoil.caching.");
661
662PyMODINIT_FUNC
663init_caching()
664{
665    /* Create the module and add the functions */
666    PyObject *m = Py_InitModule3(
667        "_caching", NULL, snakeoil_module_documentation);
668    if (!m)
669        return;
670
671    snakeoil_WeakInstMetaType.tp_base = &PyType_Type;
672
673    if (PyType_Ready(&snakeoil_WeakInstMetaType) < 0)
674        return;
675
676    if (PyType_Ready(&snakeoil_WeakValCacheType) < 0)
677        return;
678
679    if (PyType_Ready(&snakeoil_WeakValFinalizerType) < 0)
680        return;
681
682    if (!snakeoil_caching_disable_str) {
683        if (!(snakeoil_caching_disable_str =
684            PyString_FromString("disable_inst_caching")))
685            /* We can just return here, since the only way to get at
686             * this is through snakeoil_WeakInstMeta_call and that
687             * cannot be accessed yet.
688             */
689            return;
690    }
691
692    Py_INCREF(&snakeoil_WeakInstMetaType);
693    if (PyModule_AddObject(
694            m, "WeakInstMeta", (PyObject *)&snakeoil_WeakInstMetaType) == -1)
695        return;
696
697    Py_INCREF(&snakeoil_WeakValCacheType);
698    if (PyModule_AddObject(
699            m, "WeakValCache", (PyObject *)&snakeoil_WeakValCacheType) == -1)
700        return;
701
702    PyObject *cobject = PyCObject_FromVoidPtrAndDesc(
703        &snakeoil_caching_heapdefs, "NyHeapDef[] v1.0", 0);
704    if (!cobject)
705        return;
706
707    if (PyModule_AddObject(m, "_NyHeapDefs_", cobject) == -1)
708        return;
709
710    /* Success! */
711}
Note: See TracBrowser for help on using the browser.