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