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

Revision ferringb%2540gmail.com-20070327133451-49cwf0k0bobsjx7t, 15.0 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 * 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
67
68static PyTypeObject snakeoil_GetAttrProxyType = {
69    PyObject_HEAD_INIT(NULL)
70    0,                                               /* ob_size */
71    "snakeoil._klass.GetAttrProxy",                  /* tp_name */
72    sizeof(snakeoil_GetAttrProxy),                    /* tp_basicsize */
73    0,                                               /* tp_itemsize */
74    (destructor)snakeoil_GetAttrProxy_dealloc,        /* tp_dealloc */
75    0,                                               /* tp_print */
76    0,                                               /* tp_getattr */
77    0,                                               /* tp_setattr */
78    0,                                               /* tp_compare */
79    0,                                               /* tp_repr */
80    0,                                               /* tp_as_number */
81    0,                                               /* tp_as_sequence */
82    0,                                               /* tp_as_mapping */
83    0,                                               /* tp_hash  */
84    (ternaryfunc)snakeoil_GetAttrProxy_call,          /* tp_call */
85    (reprfunc)0,                                     /* tp_str */
86    0,                                               /* tp_getattro */
87    0,                                               /* tp_setattro */
88    0,                                               /* tp_as_buffer */
89    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,         /* tp_flags */
90    "GetAttrProxy object; used mainly for native __getattr__ speed",
91                                                     /* tp_doc */
92    0,                                               /* tp_traverse */
93    0,                                               /* tp_clear */
94    0,                                               /* tp_richcompare */
95    0,                                               /* tp_weaklistoffset */
96    0,                                               /* tp_iter */
97    0,                                               /* tp_iternext */
98    0,                                               /* tp_methods */
99    0,                                               /* tp_members */
100    0,                                               /* tp_getset */
101    0,                                               /* tp_base */
102    0,                                               /* tp_dict */
103    0,                                               /* tp_descr_get */
104    0,                                               /* tp_descr_set */
105    0,                                               /* tp_dictoffset */
106    0,                                               /* tp_init */
107    0,                                               /* tp_alloc */
108    snakeoil_GetAttrProxy_new,                        /* tp_new */
109
110};
111
112static PyObject *
113snakeoil_mapping_get(PyObject *self, PyObject *args)
114{
115    PyObject *key, *default_val = Py_None;
116    if(!self) {
117        PyErr_SetString(PyExc_TypeError,
118            "need to be called with a mapping as the first arg");
119        return NULL;
120    }
121    if(!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_val))
122        return NULL;
123
124    PyObject *ret = PyObject_GetItem(self, key);
125    if(ret) {
126        return ret;
127    } else if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
128        return NULL;
129    }
130
131    PyErr_Clear();
132    Py_INCREF(default_val);
133    return default_val;
134}
135
136static inline PyObject *
137internal_generic_equality(PyObject *inst1, PyObject *inst2,
138    int desired)
139{
140    if(inst1 == inst2) {
141        PyObject *res = desired == Py_EQ ? Py_True : Py_False;
142        Py_INCREF(res);
143        return res;
144    }
145
146    PyObject *attrs = PyObject_GetAttr(inst1, snakeoil_equality_attr);
147    if(!attrs)
148        return NULL;
149    if(!PyTuple_CheckExact(attrs)) {
150        PyErr_SetString(PyExc_TypeError,
151            "__attr_comparison__ must be a tuple");
152        return NULL;
153    }
154
155    Py_ssize_t idx = 0;
156    PyObject *attr1, *attr2;
157    // if Py_EQ, break on not equal, else on equal
158    for(; idx < PyTuple_GET_SIZE(attrs); idx++) {
159
160        attr1 = PyObject_GetAttr(inst1, PyTuple_GET_ITEM(attrs, idx));
161        if(!attr1) {
162            if(!PyErr_ExceptionMatches(PyExc_AttributeError))
163                return NULL;
164             PyErr_Clear();
165        }
166
167        attr2 = PyObject_GetAttr(inst2, PyTuple_GET_ITEM(attrs, idx));
168        if(!attr2) {
169            if(!PyErr_ExceptionMatches(PyExc_AttributeError)) {
170                Py_XDECREF(attr1);
171                return NULL;
172            }
173            PyErr_Clear();
174        }
175        if(!attr1) {
176            if(attr2) {
177                Py_DECREF(attr2);
178                Py_DECREF(attrs);
179                if(desired == Py_EQ) {
180                    Py_RETURN_FALSE;
181                }
182                Py_RETURN_TRUE;
183            }
184            continue;
185        } else if (!attr2) {
186            Py_DECREF(attr1);
187            Py_DECREF(attrs);
188            if(desired == Py_EQ) {
189                Py_RETURN_FALSE;
190            }
191            Py_RETURN_TRUE;
192        }
193        int ret = PyObject_RichCompareBool(attr1, attr2, desired);
194        Py_DECREF(attr1);
195        Py_DECREF(attr2);
196        if(0 > ret) {
197            Py_DECREF(attrs);
198            return NULL;
199        } else if (0 == ret) {
200            if(desired == Py_EQ) {
201                Py_DECREF(attrs);
202                Py_RETURN_FALSE;
203            }
204        } else if(desired == Py_NE) {
205            Py_DECREF(attrs);
206            Py_RETURN_TRUE;
207        }
208    }
209    Py_DECREF(attrs);
210    if(desired == Py_EQ) {
211        Py_RETURN_TRUE;
212    }
213    Py_RETURN_FALSE;
214}
215
216static PyObject *
217snakeoil_generic_equality_eq(PyObject *self, PyObject *other)
218{
219    return internal_generic_equality(self, other, Py_EQ);
220}
221
222static PyObject *
223snakeoil_generic_equality_ne(PyObject *self, PyObject *other)
224{
225    return internal_generic_equality(self, other, Py_NE);
226}
227
228snakeoil_FUNC_BINDING("generic_eq", "snakeoil._klass.generic_eq",
229    snakeoil_generic_equality_eq, METH_O|METH_COEXIST)
230
231snakeoil_FUNC_BINDING("generic_ne", "snakeoil._klass.generic_ne",
232    snakeoil_generic_equality_ne, METH_O)
233
234
235static PyMethodDef snakeoil_mapping_get_def = {
236    "get", snakeoil_mapping_get, METH_VARARGS, NULL};
237
238static PyObject *
239snakeoil_mapping_get_descr(PyObject *self, PyObject *obj, PyObject *type)
240{
241    return PyCFunction_New(&snakeoil_mapping_get_def, obj);
242}
243
244static PyTypeObject snakeoil_GetType = {
245    PyObject_HEAD_INIT(NULL)
246    0,                                               /* ob_size */
247    "snakeoil_get_type",                              /* tp_name */
248    sizeof(PyObject),                                /* tp_basicsize */
249    0,                                               /* tp_itemsize */
250    0,                                               /* tp_dealloc */
251    0,                                               /* tp_print */
252    0,                                               /* tp_getattr */
253    0,                                               /* tp_setattr */
254    0,                                               /* tp_compare */
255    0,                                               /* tp_repr */
256    0,                                               /* tp_as_number */
257    0,                                               /* tp_as_sequence */
258    0,                                               /* tp_as_mapping */
259    0,                                               /* tp_hash  */
260    0,                                               /* tp_call */
261    0,                                               /* tp_str */
262    0,                                               /* tp_getattro */
263    0,                                               /* tp_setattro */
264    0,                                               /* tp_as_buffer */
265    Py_TPFLAGS_DEFAULT,                              /* tp_flags */
266    "type of the get proxy",                         /* tp_doc */
267    0,                                               /* tp_traverse */
268    0,                                               /* tp_clear */
269    0,                                               /* tp_richcompare */
270    0,                                               /* tp_weaklistoffset */
271    0,                                               /* tp_iter */
272    0,                                               /* tp_iternext */
273    0,                                               /* tp_methods */
274    0,                                               /* tp_members */
275    0,                                               /* tp_getset */
276    0,                                               /* tp_base */
277    0,                                               /* tp_dict */
278    snakeoil_mapping_get_descr,                       /* tp_descr_get */
279    0,                                               /* tp_descr_set */
280};
281
282static PyObject *
283snakeoil_mapping_contains(PyObject *self, PyObject *key)
284{
285    if(!self) {
286        PyErr_SetString(PyExc_TypeError,
287            "need to be called with a mapping as the first arg");
288        return NULL;
289    }
290
291    PyObject *ret = PyObject_GetItem(self, key);
292    if(ret) {
293        Py_DECREF(ret);
294        ret = Py_True;
295    } else if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
296        return NULL;
297    } else {
298        PyErr_Clear();
299        ret = Py_False;
300    }
301    Py_INCREF(ret);
302    return ret;
303}
304
305static PyMethodDef snakeoil_mapping_contains_def = {
306    "contains", snakeoil_mapping_contains, METH_O|METH_COEXIST, NULL};
307
308static PyObject *
309snakeoil_mapping_contains_descr(PyObject *self, PyObject *obj, PyObject *type)
310{
311    return PyCFunction_New(&snakeoil_mapping_contains_def, obj);
312}
313
314static PyTypeObject snakeoil_ContainsType = {
315    PyObject_HEAD_INIT(NULL)
316    0,                                               /* ob_size */
317    "snakeoil_contains_type",                         /* tp_name */
318    sizeof(PyObject),                                /* tp_basicsize */
319    0,                                               /* tp_itemsize */
320    0,                                               /* tp_dealloc */
321    0,                                               /* tp_print */
322    0,                                               /* tp_getattr */
323    0,                                               /* tp_setattr */
324    0,                                               /* tp_compare */
325    0,                                               /* tp_repr */
326    0,                                               /* tp_as_number */
327    0,                                               /* tp_as_sequence */
328    0,                                               /* tp_as_mapping */
329    0,                                               /* tp_hash  */
330    0,                                               /* tp_call */
331    0,                                               /* tp_str */
332    0,                                               /* tp_getattro */
333    0,                                               /* tp_setattro */
334    0,                                               /* tp_as_buffer */
335    Py_TPFLAGS_DEFAULT,                              /* tp_flags */
336    "type of the contains proxy",                    /* tp_doc */
337    0,                                               /* tp_traverse */
338    0,                                               /* tp_clear */
339    0,                                               /* tp_richcompare */
340    0,                                               /* tp_weaklistoffset */
341    0,                                               /* tp_iter */
342    0,                                               /* tp_iternext */
343    0,                                               /* tp_methods */
344    0,                                               /* tp_members */
345    0,                                               /* tp_getset */
346    0,                                               /* tp_base */
347    0,                                               /* tp_dict */
348    snakeoil_mapping_contains_descr,                  /* tp_descr_get */
349    0,                                               /* tp_descr_set */
350};
351
352PyDoc_STRVAR(
353    snakeoil_klass_documentation,
354    "misc cpython class functionality");
355
356
357PyMODINIT_FUNC
358init_klass()
359{
360    PyObject *m = Py_InitModule3("_klass", NULL, snakeoil_klass_documentation);
361    if (!m)
362        return;
363
364    if (PyType_Ready(&snakeoil_GetAttrProxyType) < 0)
365        return;
366
367    if (PyType_Ready(&snakeoil_GetType) < 0)
368        return;
369
370    if (PyType_Ready(&snakeoil_ContainsType) < 0)
371        return;
372
373    if (PyType_Ready(&snakeoil_generic_equality_eq_type) < 0)
374        return;
375
376    if (PyType_Ready(&snakeoil_generic_equality_ne_type) < 0)
377        return;
378
379    if(!snakeoil_equality_attr) {
380        if(!(snakeoil_equality_attr = PyString_FromString(
381            "__attr_comparison__")))
382            return;
383    }
384
385    PyObject *tmp;
386    if (!(tmp = PyType_GenericNew(&snakeoil_GetType, NULL, NULL)))
387        return;
388    if (PyModule_AddObject(m, "get", tmp) == -1)
389        return;
390
391    if (!(tmp = PyType_GenericNew(&snakeoil_ContainsType, NULL, NULL)))
392        return;
393    if (PyModule_AddObject(m, "contains", tmp) == -1)
394        return;
395
396    Py_INCREF(&snakeoil_GetAttrProxyType);
397    if (PyModule_AddObject(
398            m, "GetAttrProxy", (PyObject *)&snakeoil_GetAttrProxyType) == -1)
399        return;
400
401    tmp = PyType_GenericNew(&snakeoil_generic_equality_eq_type, NULL, NULL);
402    if(!tmp)
403        return;
404    if (PyModule_AddObject(m, "generic_eq", tmp) == -1)
405        return;
406    tmp = PyType_GenericNew(&snakeoil_generic_equality_ne_type, NULL, NULL);
407    if(!tmp)
408        return;
409    if (PyModule_AddObject(m, "generic_ne", tmp) == -1)
410        return;
411}
Note: See TracBrowser for help on using the browser.