root/masterdriverz/snakeoil/src/klass.c @ masterdriverz%2540gentoo.org-20070622064834-72kwpjt4y2gzr2rp

Revision masterdriverz%2540gentoo.org-20070622064834-72kwpjt4y2gzr2rp, 15.2 kB (checked in by Charlie Shepherd <masterdriverz@…>, 19 months ago)

Fix instance method b0rkage with the cpy version of GetAttrProxy?

Line 
1/*
2 * Copyright: 2006-2007 Brian Harring <ferringb@gmail.com>
3 * License: GPL2
4 *
5 * C version of some of snakeoil (for extra speed).
6 */
7
8/* This does not really do anything since we do not use the "#"
9 * specifier in a PyArg_Parse or similar call, but hey, not using it
10 * means we are Py_ssize_t-clean too!
11 */
12
13#define PY_SSIZE_T_CLEAN
14#include "snakeoil/common.h"
15#include <ceval.h>
16
17static PyObject *snakeoil_equality_attr = NULL;
18
19typedef struct {
20    PyObject_HEAD
21    PyObject *redirect_target;
22} snakeoil_GetAttrProxy;
23
24static void
25snakeoil_GetAttrProxy_dealloc(snakeoil_GetAttrProxy *self)
26{
27    Py_CLEAR(self->redirect_target);
28    self->ob_type->tp_free((PyObject *)self);
29}
30
31static PyObject *
32snakeoil_GetAttrProxy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
33{
34    snakeoil_GetAttrProxy *self;
35    PyObject *alias_attr;
36
37    if(!PyArg_ParseTuple(args, "S:__new__", &alias_attr))
38        return NULL;
39    self = (snakeoil_GetAttrProxy *)type->tp_alloc(type, 0);
40
41    if (self) {
42        self->redirect_target = alias_attr;
43        Py_INCREF(alias_attr);
44    }
45    return (PyObject *)self;
46}
47
48static PyObject *
49snakeoil_GetAttrProxy_call(snakeoil_GetAttrProxy *self, PyObject *args,
50    PyObject *kwds)
51{
52    PyObject *attr, *real_obj, *tmp = NULL;
53
54    if(PyArg_ParseTuple(args, "OS:__call__", &real_obj, &attr)) {
55        if(Py_EnterRecursiveCall(" in GetAttrProxy.__call__ "))
56            return NULL;
57        real_obj = PyObject_GenericGetAttr(real_obj, self->redirect_target);
58        if(real_obj) {
59            tmp = PyObject_GetAttr(real_obj, attr);
60            Py_DECREF(real_obj);
61        }
62        Py_LeaveRecursiveCall();
63    }
64    return (PyObject *)tmp;
65}
66
67static PyObject *
68snakeoil_GetAttrProxy_get(PyObject *func, PyObject *obj, PyObject *type)
69{
70    if (obj == Py_None)
71        obj = NULL;
72    return PyMethod_New(func, obj, type);
73}
74
75static PyTypeObject snakeoil_GetAttrProxyType = {
76    PyObject_HEAD_INIT(NULL)
77    0,                                               /* ob_size */
78    "snakeoil._klass.GetAttrProxy",                  /* tp_name */
79    sizeof(snakeoil_GetAttrProxy),                    /* tp_basicsize */
80    0,                                               /* tp_itemsize */
81    (destructor)snakeoil_GetAttrProxy_dealloc,        /* tp_dealloc */
82    0,                                               /* tp_print */
83    0,                                               /* tp_getattr */
84    0,                                               /* tp_setattr */
85    0,                                               /* tp_compare */
86    0,                                               /* tp_repr */
87    0,                                               /* tp_as_number */
88    0,                                               /* tp_as_sequence */
89    0,                                               /* tp_as_mapping */
90    0,                                               /* tp_hash  */
91    (ternaryfunc)snakeoil_GetAttrProxy_call,          /* tp_call */
92    (reprfunc)0,                                     /* tp_str */
93    0,                                               /* tp_getattro */
94    0,                                               /* tp_setattro */
95    0,                                               /* tp_as_buffer */
96    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,         /* tp_flags */
97    "GetAttrProxy object; used mainly for native __getattr__ speed",
98                                                     /* tp_doc */
99    0,                                               /* tp_traverse */
100    0,                                               /* tp_clear */
101    0,                                               /* tp_richcompare */
102    0,                                               /* tp_weaklistoffset */
103    0,                                               /* tp_iter */
104    0,                                               /* tp_iternext */
105    0,                                               /* tp_methods */
106    0,                                               /* tp_members */
107    0,                                               /* tp_getset */
108    0,                                               /* tp_base */
109    0,                                               /* tp_dict */
110    snakeoil_GetAttrProxy_get,                       /* tp_descr_get */
111    0,                                               /* tp_descr_set */
112    0,                                               /* tp_dictoffset */
113    0,                                               /* tp_init */
114    0,                                               /* tp_alloc */
115    snakeoil_GetAttrProxy_new,                        /* tp_new */
116
117};
118
119static PyObject *
120snakeoil_mapping_get(PyObject *self, PyObject *args)
121{
122    PyObject *key, *default_val = Py_None;
123    if(!self) {
124        PyErr_SetString(PyExc_TypeError,
125            "need to be called with a mapping as the first arg");
126        return NULL;
127    }
128    if(!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_val))
129        return NULL;
130
131    PyObject *ret = PyObject_GetItem(self, key);
132    if(ret) {
133        return ret;
134    } else if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
135        return NULL;
136    }
137
138    PyErr_Clear();
139    Py_INCREF(default_val);
140    return default_val;
141}
142
143static inline PyObject *
144internal_generic_equality(PyObject *inst1, PyObject *inst2,
145    int desired)
146{
147    if(inst1 == inst2) {
148        PyObject *res = desired == Py_EQ ? Py_True : Py_False;
149        Py_INCREF(res);
150        return res;
151    }
152
153    PyObject *attrs = PyObject_GetAttr(inst1, snakeoil_equality_attr);
154    if(!attrs)
155        return NULL;
156    if(!PyTuple_CheckExact(attrs)) {
157        PyErr_SetString(PyExc_TypeError,
158            "__attr_comparison__ must be a tuple");
159        return NULL;
160    }
161
162    Py_ssize_t idx = 0;
163    PyObject *attr1, *attr2;
164    // if Py_EQ, break on not equal, else on equal
165    for(; idx < PyTuple_GET_SIZE(attrs); idx++) {
166
167        attr1 = PyObject_GetAttr(inst1, PyTuple_GET_ITEM(attrs, idx));
168        if(!attr1) {
169            if(!PyErr_ExceptionMatches(PyExc_AttributeError))
170                return NULL;
171             PyErr_Clear();
172        }
173
174        attr2 = PyObject_GetAttr(inst2, PyTuple_GET_ITEM(attrs, idx));
175        if(!attr2) {
176            if(!PyErr_ExceptionMatches(PyExc_AttributeError)) {
177                Py_XDECREF(attr1);
178                return NULL;
179            }
180            PyErr_Clear();
181        }
182        if(!attr1) {
183            if(attr2) {
184                Py_DECREF(attr2);
185                Py_DECREF(attrs);
186                if(desired == Py_EQ) {
187                    Py_RETURN_FALSE;
188                }
189                Py_RETURN_TRUE;
190            }
191            continue;
192        } else if (!attr2) {
193            Py_DECREF(attr1);
194            Py_DECREF(attrs);
195            if(desired == Py_EQ) {
196                Py_RETURN_FALSE;
197            }
198            Py_RETURN_TRUE;
199        }
200        int ret = PyObject_RichCompareBool(attr1, attr2, desired);
201        Py_DECREF(attr1);
202        Py_DECREF(attr2);
203        if(0 > ret) {
204            Py_DECREF(attrs);
205            return NULL;
206        } else if (0 == ret) {
207            if(desired == Py_EQ) {
208                Py_DECREF(attrs);
209                Py_RETURN_FALSE;
210            }
211        } else if(desired == Py_NE) {
212            Py_DECREF(attrs);
213            Py_RETURN_TRUE;
214        }
215    }
216    Py_DECREF(attrs);
217    if(desired == Py_EQ) {
218        Py_RETURN_TRUE;
219    }
220    Py_RETURN_FALSE;
221}
222
223static PyObject *
224snakeoil_generic_equality_eq(PyObject *self, PyObject *other)
225{
226    return internal_generic_equality(self, other, Py_EQ);
227}
228
229static PyObject *
230snakeoil_generic_equality_ne(PyObject *self, PyObject *other)
231{
232    return internal_generic_equality(self, other, Py_NE);
233}
234
235snakeoil_FUNC_BINDING("generic_eq", "snakeoil._klass.generic_eq",
236    snakeoil_generic_equality_eq, METH_O|METH_COEXIST)
237
238snakeoil_FUNC_BINDING("generic_ne", "snakeoil._klass.generic_ne",
239    snakeoil_generic_equality_ne, METH_O)
240
241
242static PyMethodDef snakeoil_mapping_get_def = {
243    "get", snakeoil_mapping_get, METH_VARARGS, NULL};
244
245static PyObject *
246snakeoil_mapping_get_descr(PyObject *self, PyObject *obj, PyObject *type)
247{
248    return PyCFunction_New(&snakeoil_mapping_get_def, obj);
249}
250
251static PyTypeObject snakeoil_GetType = {
252    PyObject_HEAD_INIT(NULL)
253    0,                                               /* ob_size */
254    "snakeoil_get_type",                              /* tp_name */
255    sizeof(PyObject),                                /* tp_basicsize */
256    0,                                               /* tp_itemsize */
257    0,                                               /* tp_dealloc */
258    0,                                               /* tp_print */
259    0,                                               /* tp_getattr */
260    0,                                               /* tp_setattr */
261    0,                                               /* tp_compare */
262    0,                                               /* tp_repr */
263    0,                                               /* tp_as_number */
264    0,                                               /* tp_as_sequence */
265    0,                                               /* tp_as_mapping */
266    0,                                               /* tp_hash  */
267    0,                                               /* tp_call */
268    0,                                               /* tp_str */
269    0,                                               /* tp_getattro */
270    0,                                               /* tp_setattro */
271    0,                                               /* tp_as_buffer */
272    Py_TPFLAGS_DEFAULT,                              /* tp_flags */
273    "type of the get proxy",                         /* tp_doc */
274    0,                                               /* tp_traverse */
275    0,                                               /* tp_clear */
276    0,                                               /* tp_richcompare */
277    0,                                               /* tp_weaklistoffset */
278    0,                                               /* tp_iter */
279    0,                                               /* tp_iternext */
280    0,                                               /* tp_methods */
281    0,                                               /* tp_members */
282    0,                                               /* tp_getset */
283    0,                                               /* tp_base */
284    0,                                               /* tp_dict */
285    snakeoil_mapping_get_descr,                       /* tp_descr_get */
286    0,                                               /* tp_descr_set */
287};
288
289static PyObject *
290snakeoil_mapping_contains(PyObject *self, PyObject *key)
291{
292    if(!self) {
293        PyErr_SetString(PyExc_TypeError,
294            "need to be called with a mapping as the first arg");
295        return NULL;
296    }
297
298    PyObject *ret = PyObject_GetItem(self, key);
299    if(ret) {
300        Py_DECREF(ret);
301        ret = Py_True;
302    } else if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
303        return NULL;
304    } else {
305        PyErr_Clear();
306        ret = Py_False;
307    }
308    Py_INCREF(ret);
309    return ret;
310}
311
312static PyMethodDef snakeoil_mapping_contains_def = {
313    "contains", snakeoil_mapping_contains, METH_O|METH_COEXIST, NULL};
314
315static PyObject *
316snakeoil_mapping_contains_descr(PyObject *self, PyObject *obj, PyObject *type)
317{
318    return PyCFunction_New(&snakeoil_mapping_contains_def, obj);
319}
320
321static PyTypeObject snakeoil_ContainsType = {
322    PyObject_HEAD_INIT(NULL)
323    0,                                               /* ob_size */
324    "snakeoil_contains_type",                         /* tp_name */
325    sizeof(PyObject),                                /* tp_basicsize */
326    0,                                               /* tp_itemsize */
327    0,                                               /* tp_dealloc */
328    0,                                               /* tp_print */
329    0,                                               /* tp_getattr */
330    0,                                               /* tp_setattr */
331    0,                                               /* tp_compare */
332    0,                                               /* tp_repr */
333    0,                                               /* tp_as_number */
334    0,                                               /* tp_as_sequence */
335    0,                                               /* tp_as_mapping */
336    0,                                               /* tp_hash  */
337    0,                                               /* tp_call */
338    0,                                               /* tp_str */
339    0,                                               /* tp_getattro */
340    0,                                               /* tp_setattro */
341    0,                                               /* tp_as_buffer */
342    Py_TPFLAGS_DEFAULT,                              /* tp_flags */
343    "type of the contains proxy",                    /* tp_doc */
344    0,                                               /* tp_traverse */
345    0,                                               /* tp_clear */
346    0,                                               /* tp_richcompare */
347    0,                                               /* tp_weaklistoffset */
348    0,                                               /* tp_iter */
349    0,                                               /* tp_iternext */
350    0,                                               /* tp_methods */
351    0,                                               /* tp_members */
352    0,                                               /* tp_getset */
353    0,                                               /* tp_base */
354    0,                                               /* tp_dict */
355    snakeoil_mapping_contains_descr,                  /* tp_descr_get */
356    0,                                               /* tp_descr_set */
357};
358
359PyDoc_STRVAR(
360    snakeoil_klass_documentation,
361    "misc cpython class functionality");
362
363
364PyMODINIT_FUNC
365init_klass()
366{
367    PyObject *m = Py_InitModule3("_klass", NULL, snakeoil_klass_documentation);
368    if (!m)
369        return;
370
371    if (PyType_Ready(&snakeoil_GetAttrProxyType) < 0)
372        return;
373
374    if (PyType_Ready(&snakeoil_GetType) < 0)
375        return;
376
377    if (PyType_Ready(&snakeoil_ContainsType) < 0)
378        return;
379
380    if (PyType_Ready(&snakeoil_generic_equality_eq_type) < 0)
381        return;
382
383    if (PyType_Ready(&snakeoil_generic_equality_ne_type) < 0)
384        return;
385
386    if(!snakeoil_equality_attr) {
387        if(!(snakeoil_equality_attr = PyString_FromString(
388            "__attr_comparison__")))
389            return;
390    }
391
392    PyObject *tmp;
393    if (!(tmp = PyType_GenericNew(&snakeoil_GetType, NULL, NULL)))
394        return;
395    if (PyModule_AddObject(m, "get", tmp) == -1)
396        return;
397
398    if (!(tmp = PyType_GenericNew(&snakeoil_ContainsType, NULL, NULL)))
399        return;
400    if (PyModule_AddObject(m, "contains", tmp) == -1)
401        return;
402
403    Py_INCREF(&snakeoil_GetAttrProxyType);
404    if (PyModule_AddObject(
405            m, "GetAttrProxy", (PyObject *)&snakeoil_GetAttrProxyType) == -1)
406        return;
407
408    tmp = PyType_GenericNew(&snakeoil_generic_equality_eq_type, NULL, NULL);
409    if(!tmp)
410        return;
411    if (PyModule_AddObject(m, "generic_eq", tmp) == -1)
412        return;
413    tmp = PyType_GenericNew(&snakeoil_generic_equality_ne_type, NULL, NULL);
414    if(!tmp)
415        return;
416    if (PyModule_AddObject(m, "generic_ne", tmp) == -1)
417        return;
418}
Note: See TracBrowser for help on using the browser.