• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Cell object implementation */
2 
3 #include "Python.h"
4 #include "pycore_object.h"
5 
6 PyObject *
PyCell_New(PyObject * obj)7 PyCell_New(PyObject *obj)
8 {
9     PyCellObject *op;
10 
11     op = (PyCellObject *)PyObject_GC_New(PyCellObject, &PyCell_Type);
12     if (op == NULL)
13         return NULL;
14     op->ob_ref = obj;
15     Py_XINCREF(obj);
16 
17     _PyObject_GC_TRACK(op);
18     return (PyObject *)op;
19 }
20 
21 PyDoc_STRVAR(cell_new_doc,
22 "cell([contents])\n"
23 "--\n"
24 "\n"
25 "Create a new cell object.\n"
26 "\n"
27 "  contents\n"
28 "    the contents of the cell. If not specified, the cell will be empty,\n"
29 "    and \n further attempts to access its cell_contents attribute will\n"
30 "    raise a ValueError.");
31 
32 
33 static PyObject *
cell_new(PyTypeObject * type,PyObject * args,PyObject * kwargs)34 cell_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
35 {
36     PyObject *return_value = NULL;
37     PyObject *obj = NULL;
38 
39     if (!_PyArg_NoKeywords("cell", kwargs)) {
40         goto exit;
41     }
42     /* min = 0: we allow the cell to be empty */
43     if (!PyArg_UnpackTuple(args, "cell", 0, 1, &obj)) {
44         goto exit;
45     }
46     return_value = PyCell_New(obj);
47 
48 exit:
49     return return_value;
50 }
51 
52 PyObject *
PyCell_Get(PyObject * op)53 PyCell_Get(PyObject *op)
54 {
55     if (!PyCell_Check(op)) {
56         PyErr_BadInternalCall();
57         return NULL;
58     }
59     Py_XINCREF(((PyCellObject*)op)->ob_ref);
60     return PyCell_GET(op);
61 }
62 
63 int
PyCell_Set(PyObject * op,PyObject * obj)64 PyCell_Set(PyObject *op, PyObject *obj)
65 {
66     PyObject* oldobj;
67     if (!PyCell_Check(op)) {
68         PyErr_BadInternalCall();
69         return -1;
70     }
71     oldobj = PyCell_GET(op);
72     Py_XINCREF(obj);
73     PyCell_SET(op, obj);
74     Py_XDECREF(oldobj);
75     return 0;
76 }
77 
78 static void
cell_dealloc(PyCellObject * op)79 cell_dealloc(PyCellObject *op)
80 {
81     _PyObject_GC_UNTRACK(op);
82     Py_XDECREF(op->ob_ref);
83     PyObject_GC_Del(op);
84 }
85 
86 static PyObject *
cell_richcompare(PyObject * a,PyObject * b,int op)87 cell_richcompare(PyObject *a, PyObject *b, int op)
88 {
89     /* neither argument should be NULL, unless something's gone wrong */
90     assert(a != NULL && b != NULL);
91 
92     /* both arguments should be instances of PyCellObject */
93     if (!PyCell_Check(a) || !PyCell_Check(b)) {
94         Py_RETURN_NOTIMPLEMENTED;
95     }
96 
97     /* compare cells by contents; empty cells come before anything else */
98     a = ((PyCellObject *)a)->ob_ref;
99     b = ((PyCellObject *)b)->ob_ref;
100     if (a != NULL && b != NULL)
101         return PyObject_RichCompare(a, b, op);
102 
103     Py_RETURN_RICHCOMPARE(b == NULL, a == NULL, op);
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, Py_TYPE(op->ob_ref)->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 int
cell_set_contents(PyCellObject * op,PyObject * obj,void * Py_UNUSED (ignored))144 cell_set_contents(PyCellObject *op, PyObject *obj, void *Py_UNUSED(ignored))
145 {
146     Py_XINCREF(obj);
147     Py_XSETREF(op->ob_ref, obj);
148     return 0;
149 }
150 
151 static PyGetSetDef cell_getsetlist[] = {
152     {"cell_contents", (getter)cell_get_contents,
153                       (setter)cell_set_contents, NULL},
154     {NULL} /* sentinel */
155 };
156 
157 PyTypeObject PyCell_Type = {
158     PyVarObject_HEAD_INIT(&PyType_Type, 0)
159     "cell",
160     sizeof(PyCellObject),
161     0,
162     (destructor)cell_dealloc,                   /* tp_dealloc */
163     0,                                          /* tp_vectorcall_offset */
164     0,                                          /* tp_getattr */
165     0,                                          /* tp_setattr */
166     0,                                          /* tp_as_async */
167     (reprfunc)cell_repr,                        /* tp_repr */
168     0,                                          /* tp_as_number */
169     0,                                          /* tp_as_sequence */
170     0,                                          /* tp_as_mapping */
171     0,                                          /* tp_hash */
172     0,                                          /* tp_call */
173     0,                                          /* tp_str */
174     PyObject_GenericGetAttr,                    /* tp_getattro */
175     0,                                          /* tp_setattro */
176     0,                                          /* tp_as_buffer */
177     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
178     cell_new_doc,                               /* tp_doc */
179     (traverseproc)cell_traverse,                /* tp_traverse */
180     (inquiry)cell_clear,                        /* tp_clear */
181     cell_richcompare,                           /* tp_richcompare */
182     0,                                          /* tp_weaklistoffset */
183     0,                                          /* tp_iter */
184     0,                                          /* tp_iternext */
185     0,                                          /* tp_methods */
186     0,                                          /* tp_members */
187     cell_getsetlist,                            /* tp_getset */
188     0,                                          /* tp_base */
189     0,                                          /* tp_dict */
190     0,                                          /* tp_descr_get */
191     0,                                          /* tp_descr_set */
192     0,                                          /* tp_dictoffset */
193     0,                                          /* tp_init */
194     0,                                          /* tp_alloc */
195     (newfunc)cell_new,                          /* tp_new */
196     0,                                          /* tp_free */
197 };
198