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