• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Cell object implementation */
2 
3 #include "Python.h"
4 
5 PyObject *
PyCell_New(PyObject * obj)6 PyCell_New(PyObject *obj)
7 {
8     PyCellObject *op;
9 
10     op = (PyCellObject *)PyObject_GC_New(PyCellObject, &PyCell_Type);
11     if (op == NULL)
12         return NULL;
13     op->ob_ref = obj;
14     Py_XINCREF(obj);
15 
16     _PyObject_GC_TRACK(op);
17     return (PyObject *)op;
18 }
19 
20 PyObject *
PyCell_Get(PyObject * op)21 PyCell_Get(PyObject *op)
22 {
23     if (!PyCell_Check(op)) {
24         PyErr_BadInternalCall();
25         return NULL;
26     }
27     Py_XINCREF(((PyCellObject*)op)->ob_ref);
28     return PyCell_GET(op);
29 }
30 
31 int
PyCell_Set(PyObject * op,PyObject * obj)32 PyCell_Set(PyObject *op, PyObject *obj)
33 {
34     PyObject* oldobj;
35     if (!PyCell_Check(op)) {
36         PyErr_BadInternalCall();
37         return -1;
38     }
39     oldobj = PyCell_GET(op);
40     Py_XINCREF(obj);
41     PyCell_SET(op, obj);
42     Py_XDECREF(oldobj);
43     return 0;
44 }
45 
46 static void
cell_dealloc(PyCellObject * op)47 cell_dealloc(PyCellObject *op)
48 {
49     _PyObject_GC_UNTRACK(op);
50     Py_XDECREF(op->ob_ref);
51     PyObject_GC_Del(op);
52 }
53 
54 #define TEST_COND(cond) ((cond) ? Py_True : Py_False)
55 
56 static PyObject *
cell_richcompare(PyObject * a,PyObject * b,int op)57 cell_richcompare(PyObject *a, PyObject *b, int op)
58 {
59     int result;
60     PyObject *v;
61 
62     /* neither argument should be NULL, unless something's gone wrong */
63     assert(a != NULL && b != NULL);
64 
65     /* both arguments should be instances of PyCellObject */
66     if (!PyCell_Check(a) || !PyCell_Check(b)) {
67         v = Py_NotImplemented;
68         Py_INCREF(v);
69         return v;
70     }
71 
72     /* compare cells by contents; empty cells come before anything else */
73     a = ((PyCellObject *)a)->ob_ref;
74     b = ((PyCellObject *)b)->ob_ref;
75     if (a != NULL && b != NULL)
76         return PyObject_RichCompare(a, b, op);
77 
78     result = (b == NULL) - (a == NULL);
79     switch (op) {
80     case Py_EQ:
81         v = TEST_COND(result == 0);
82         break;
83     case Py_NE:
84         v = TEST_COND(result != 0);
85         break;
86     case Py_LE:
87         v = TEST_COND(result <= 0);
88         break;
89     case Py_GE:
90         v = TEST_COND(result >= 0);
91         break;
92     case Py_LT:
93         v = TEST_COND(result < 0);
94         break;
95     case Py_GT:
96         v = TEST_COND(result > 0);
97         break;
98     default:
99         PyErr_BadArgument();
100         return NULL;
101     }
102     Py_INCREF(v);
103     return v;
104 }
105 
106 static PyObject *
cell_repr(PyCellObject * op)107 cell_repr(PyCellObject *op)
108 {
109     if (op->ob_ref == NULL)
110         return PyUnicode_FromFormat("<cell at %p: empty>", op);
111 
112     return PyUnicode_FromFormat("<cell at %p: %.80s object at %p>",
113                                op, op->ob_ref->ob_type->tp_name,
114                                op->ob_ref);
115 }
116 
117 static int
cell_traverse(PyCellObject * op,visitproc visit,void * arg)118 cell_traverse(PyCellObject *op, visitproc visit, void *arg)
119 {
120     Py_VISIT(op->ob_ref);
121     return 0;
122 }
123 
124 static int
cell_clear(PyCellObject * op)125 cell_clear(PyCellObject *op)
126 {
127     Py_CLEAR(op->ob_ref);
128     return 0;
129 }
130 
131 static PyObject *
cell_get_contents(PyCellObject * op,void * closure)132 cell_get_contents(PyCellObject *op, void *closure)
133 {
134     if (op->ob_ref == NULL)
135     {
136         PyErr_SetString(PyExc_ValueError, "Cell is empty");
137         return NULL;
138     }
139     Py_INCREF(op->ob_ref);
140     return op->ob_ref;
141 }
142 
143 static PyGetSetDef cell_getsetlist[] = {
144     {"cell_contents", (getter)cell_get_contents, NULL},
145     {NULL} /* sentinel */
146 };
147 
148 PyTypeObject PyCell_Type = {
149     PyVarObject_HEAD_INIT(&PyType_Type, 0)
150     "cell",
151     sizeof(PyCellObject),
152     0,
153     (destructor)cell_dealloc,                   /* tp_dealloc */
154     0,                                          /* tp_print */
155     0,                                          /* tp_getattr */
156     0,                                          /* tp_setattr */
157     0,                                          /* tp_reserved */
158     (reprfunc)cell_repr,                        /* tp_repr */
159     0,                                          /* tp_as_number */
160     0,                                          /* tp_as_sequence */
161     0,                                          /* tp_as_mapping */
162     0,                                          /* tp_hash */
163     0,                                          /* tp_call */
164     0,                                          /* tp_str */
165     PyObject_GenericGetAttr,                    /* tp_getattro */
166     0,                                          /* tp_setattro */
167     0,                                          /* tp_as_buffer */
168     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
169     0,                                          /* tp_doc */
170     (traverseproc)cell_traverse,                /* tp_traverse */
171     (inquiry)cell_clear,                        /* tp_clear */
172     cell_richcompare,                           /* tp_richcompare */
173     0,                                          /* tp_weaklistoffset */
174     0,                                          /* tp_iter */
175     0,                                          /* tp_iternext */
176     0,                                          /* tp_methods */
177     0,                                          /* tp_members */
178     cell_getsetlist,                            /* tp_getset */
179 };
180