root/releases/pkgcore/0.2.3/src/klass.c @ ferringb%2540gmail.com-20070212033114-bnsgqv0v5n9y98kg

Revision ferringb%2540gmail.com-20070212033114-bnsgqv0v5n9y98kg, 14.5 KB (checked in by Brian Harring <ferringb@…>, 2 years ago)

bit of cleanup of the code; still needs a full walk since majority of it is quickies, but tiz a start.

Line 
1/*
2 * Copyright: 2006 Brian Harring <ferringb@gmail.com>
3 * License: GPL2
4 *
5 * C version of some of pkgcore (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 "common.h"
15#include <ceval.h>
16
17static PyObject *pkgcore_equality_attr = NULL;
18
19typedef struct {
20    PyObject_HEAD
21    PyObject *redirect_target;
22} pkgcore_GetAttrProxy;
23
24static void
25pkgcore_GetAttrProxy_dealloc(pkgcore_GetAttrProxy *self)
26{
27    Py_CLEAR(self->redirect_target);
28    self->ob_type->tp_free((PyObject *)self);
29}
30
31static PyObject *
32pkgcore_GetAttrProxy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
33{
34    pkgcore_GetAttrProxy *self;
35    PyObject *alias_attr;
36
37    if(!PyArg_ParseTuple(args, "S:__new__", &alias_attr))
38        return NULL;
39    self = (pkgcore_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 *
49pkgcore_GetAttrProxy_call(pkgcore_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 pkgcore_GetAttrProxyType = {
69    PyObject_HEAD_INIT(NULL)
70    0,                                               /* ob_size */
71    "pkgcore.util._klass.GetAttrProxy",              /* tp_name */
72    sizeof(pkgcore_GetAttrProxy),                    /* tp_basicsize */
73    0,                                               /* tp_itemsize */
74    (destructor)pkgcore_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)pkgcore_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    pkgcore_GetAttrProxy_new,                        /* tp_new */
109
110};
111
112static PyObject *
113pkgcore_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, pkgcore_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        if(!(attr1 = PyObject_GetAttr(inst1,
160            PyTuple_GET_ITEM(attrs, idx)))) {
161            if(PyErr_ExceptionMatches(PyExc_AttributeError)) {
162                PyErr_Clear();
163                if(desired == Py_EQ) {
164                    Py_RETURN_FALSE;
165                }
166                Py_RETURN_TRUE;
167            }
168            return NULL;
169        }
170        if(!(attr2 = PyObject_GetAttr(inst2,
171            PyTuple_GET_ITEM(attrs, idx)))) {
172            Py_DECREF(attr1);
173            if(PyErr_ExceptionMatches(PyExc_AttributeError)) {
174                PyErr_Clear();
175                if(desired == Py_EQ) {
176                    Py_RETURN_FALSE;
177                }
178                Py_RETURN_TRUE;
179            }
180            return NULL;
181        }
182        int ret = PyObject_RichCompareBool(attr1, attr2, desired);
183        Py_DECREF(attr1);
184        Py_DECREF(attr2);
185        if(ret == -1) {
186            return NULL;
187        } else if (ret == 0) {
188            Py_INCREF(Py_False);
189            return Py_False;
190        }
191    }
192    Py_INCREF(Py_True);
193    return Py_True;
194}
195
196static PyObject *
197pkgcore_generic_equality_eq(PyObject *self, PyObject *other)
198{
199    return internal_generic_equality(self, other, Py_EQ);
200}
201
202static PyObject *
203pkgcore_generic_equality_ne(PyObject *self, PyObject *other)
204{
205    return internal_generic_equality(self, other, Py_NE);
206}
207
208PKGCORE_FUNC_BINDING("generic_eq", "pkgcore.util._klass.generic_eq",
209    pkgcore_generic_equality_eq, METH_O|METH_COEXIST)
210
211PKGCORE_FUNC_BINDING("generic_ne", "pkgcore.util._klass.generic_ne",
212    pkgcore_generic_equality_ne, METH_O)
213   
214
215static PyMethodDef pkgcore_mapping_get_def = {
216    "get", pkgcore_mapping_get, METH_VARARGS, NULL};
217
218static PyObject *
219pkgcore_mapping_get_descr(PyObject *self, PyObject *obj, PyObject *type)
220{
221    return PyCFunction_New(&pkgcore_mapping_get_def, obj);
222}
223
224static PyTypeObject pkgcore_GetType = {
225    PyObject_HEAD_INIT(NULL)
226    0,                                               /* ob_size */
227    "pkgcore_get_type",                              /* tp_name */
228    sizeof(PyObject),                                /* tp_basicsize */
229    0,                                               /* tp_itemsize */
230    0,                                               /* tp_dealloc */
231    0,                                               /* tp_print */
232    0,                                               /* tp_getattr */
233    0,                                               /* tp_setattr */
234    0,                                               /* tp_compare */
235    0,                                               /* tp_repr */
236    0,                                               /* tp_as_number */
237    0,                                               /* tp_as_sequence */
238    0,                                               /* tp_as_mapping */
239    0,                                               /* tp_hash  */
240    0,                                               /* tp_call */
241    0,                                               /* tp_str */
242    0,                                               /* tp_getattro */
243    0,                                               /* tp_setattro */
244    0,                                               /* tp_as_buffer */
245    Py_TPFLAGS_DEFAULT,                              /* tp_flags */
246    "type of the get proxy",                         /* tp_doc */
247    0,                                               /* tp_traverse */
248    0,                                               /* tp_clear */
249    0,                                               /* tp_richcompare */
250    0,                                               /* tp_weaklistoffset */
251    0,                                               /* tp_iter */
252    0,                                               /* tp_iternext */
253    0,                                               /* tp_methods */
254    0,                                               /* tp_members */
255    0,                                               /* tp_getset */
256    0,                                               /* tp_base */
257    0,                                               /* tp_dict */
258    pkgcore_mapping_get_descr,                       /* tp_descr_get */
259    0,                                               /* tp_descr_set */
260};
261
262static PyObject *
263pkgcore_mapping_contains(PyObject *self, PyObject *key)
264{
265    if(!self) {
266        PyErr_SetString(PyExc_TypeError,
267            "need to be called with a mapping as the first arg");
268        return NULL;
269    }
270
271    PyObject *ret = PyObject_GetItem(self, key);
272    if(ret) {
273        Py_DECREF(ret);
274        ret = Py_True;
275    } else if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
276        return NULL;
277    } else {
278        PyErr_Clear();
279        ret = Py_False;
280    }
281    Py_INCREF(ret);
282    return ret;
283}
284
285static PyMethodDef pkgcore_mapping_contains_def = {
286    "contains", pkgcore_mapping_contains, METH_O|METH_COEXIST, NULL};
287
288static PyObject *
289pkgcore_mapping_contains_descr(PyObject *self, PyObject *obj, PyObject *type)
290{
291    return PyCFunction_New(&pkgcore_mapping_contains_def, obj);
292}
293
294static PyTypeObject pkgcore_ContainsType = {
295    PyObject_HEAD_INIT(NULL)
296    0,                                               /* ob_size */
297    "pkgcore_contains_type",                         /* tp_name */
298    sizeof(PyObject),                                /* tp_basicsize */
299    0,                                               /* tp_itemsize */
300    0,                                               /* tp_dealloc */
301    0,                                               /* tp_print */
302    0,                                               /* tp_getattr */
303    0,                                               /* tp_setattr */
304    0,                                               /* tp_compare */
305    0,                                               /* tp_repr */
306    0,                                               /* tp_as_number */
307    0,                                               /* tp_as_sequence */
308    0,                                               /* tp_as_mapping */
309    0,                                               /* tp_hash  */
310    0,                                               /* tp_call */
311    0,                                               /* tp_str */
312    0,                                               /* tp_getattro */
313    0,                                               /* tp_setattro */
314    0,                                               /* tp_as_buffer */
315    Py_TPFLAGS_DEFAULT,                              /* tp_flags */
316    "type of the contains proxy",                    /* tp_doc */
317    0,                                               /* tp_traverse */
318    0,                                               /* tp_clear */
319    0,                                               /* tp_richcompare */
320    0,                                               /* tp_weaklistoffset */
321    0,                                               /* tp_iter */
322    0,                                               /* tp_iternext */
323    0,                                               /* tp_methods */
324    0,                                               /* tp_members */
325    0,                                               /* tp_getset */
326    0,                                               /* tp_base */
327    0,                                               /* tp_dict */
328    pkgcore_mapping_contains_descr,                  /* tp_descr_get */
329    0,                                               /* tp_descr_set */
330};
331
332PyDoc_STRVAR(
333    pkgcore_klass_documentation,
334    "misc cpython class functionality");
335
336
337PyMODINIT_FUNC
338init_klass()
339{
340    PyObject *m = Py_InitModule3("_klass", NULL, pkgcore_klass_documentation);
341    if (!m)
342        return;
343
344    if (PyType_Ready(&pkgcore_GetAttrProxyType) < 0)
345        return;
346
347    if (PyType_Ready(&pkgcore_GetType) < 0)
348        return;
349
350    if (PyType_Ready(&pkgcore_ContainsType) < 0)
351        return;
352
353    if (PyType_Ready(&pkgcore_generic_equality_eq_type) < 0)
354        return;
355
356    if (PyType_Ready(&pkgcore_generic_equality_ne_type) < 0)
357        return;
358
359    if(!pkgcore_equality_attr) {
360        if(!(pkgcore_equality_attr = PyString_FromString(
361            "__attr_comparison__")))
362            return;
363    }
364
365    PyObject *tmp;
366    if (!(tmp = PyType_GenericNew(&pkgcore_GetType, NULL, NULL)))
367        return;
368    if (PyModule_AddObject(m, "get", tmp) == -1)
369        return;
370
371    if (!(tmp = PyType_GenericNew(&pkgcore_ContainsType, NULL, NULL)))
372        return;
373    if (PyModule_AddObject(m, "contains", tmp) == -1)
374        return;
375
376    Py_INCREF(&pkgcore_GetAttrProxyType);
377    if (PyModule_AddObject(
378            m, "GetAttrProxy", (PyObject *)&pkgcore_GetAttrProxyType) == -1)
379        return;
380
381    tmp = PyType_GenericNew(&pkgcore_generic_equality_eq_type, NULL, NULL);
382    if(!tmp)
383        return;
384    if (PyModule_AddObject(m, "generic_eq", tmp) == -1)
385        return;
386    tmp = PyType_GenericNew(&pkgcore_generic_equality_ne_type, NULL, NULL);
387    if(!tmp)
388        return;
389    if (PyModule_AddObject(m, "generic_ne", tmp) == -1)
390        return;
391}
Note: See TracBrowser for help on using the browser.