xref: /third_party/python/Objects/cellobject.c (revision 7db96d56)
1/* Cell object implementation */
2
3#include "Python.h"
4#include "pycore_object.h"
5
6PyObject *
7PyCell_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
21PyDoc_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
33static PyObject *
34cell_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
48exit:
49    return return_value;
50}
51
52PyObject *
53PyCell_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
63int
64PyCell_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
78static void
79cell_dealloc(PyCellObject *op)
80{
81    _PyObject_GC_UNTRACK(op);
82    Py_XDECREF(op->ob_ref);
83    PyObject_GC_Del(op);
84}
85
86static PyObject *
87cell_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
106static PyObject *
107cell_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
117static int
118cell_traverse(PyCellObject *op, visitproc visit, void *arg)
119{
120    Py_VISIT(op->ob_ref);
121    return 0;
122}
123
124static int
125cell_clear(PyCellObject *op)
126{
127    Py_CLEAR(op->ob_ref);
128    return 0;
129}
130
131static PyObject *
132cell_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
143static int
144cell_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
151static PyGetSetDef cell_getsetlist[] = {
152    {"cell_contents", (getter)cell_get_contents,
153                      (setter)cell_set_contents, NULL},
154    {NULL} /* sentinel */
155};
156
157PyTypeObject 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