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