1/* Cell object implementation */
2
3#include "Python.h"
4
5PyObject *
6PyCell_New(PyObject *obj)
7{
8    PyCellObject *op;
9
10    op = (PyCellObject *)PyObject_GC_New(PyCellObject, &PyCell_Type);
11    if (op == NULL)
12        return NULL;
13    op->ob_ref = obj;
14    Py_XINCREF(obj);
15
16    _PyObject_GC_TRACK(op);
17    return (PyObject *)op;
18}
19
20PyObject *
21PyCell_Get(PyObject *op)
22{
23    if (!PyCell_Check(op)) {
24        PyErr_BadInternalCall();
25        return NULL;
26    }
27    Py_XINCREF(((PyCellObject*)op)->ob_ref);
28    return PyCell_GET(op);
29}
30
31int
32PyCell_Set(PyObject *op, PyObject *obj)
33{
34    PyObject* oldobj;
35    if (!PyCell_Check(op)) {
36        PyErr_BadInternalCall();
37        return -1;
38    }
39    oldobj = PyCell_GET(op);
40    Py_XINCREF(obj);
41    PyCell_SET(op, obj);
42    Py_XDECREF(oldobj);
43    return 0;
44}
45
46static void
47cell_dealloc(PyCellObject *op)
48{
49    _PyObject_GC_UNTRACK(op);
50    Py_XDECREF(op->ob_ref);
51    PyObject_GC_Del(op);
52}
53
54#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
55
56static PyObject *
57cell_richcompare(PyObject *a, PyObject *b, int op)
58{
59    int result;
60    PyObject *v;
61
62    /* neither argument should be NULL, unless something's gone wrong */
63    assert(a != NULL && b != NULL);
64
65    /* both arguments should be instances of PyCellObject */
66    if (!PyCell_Check(a) || !PyCell_Check(b)) {
67        v = Py_NotImplemented;
68        Py_INCREF(v);
69        return v;
70    }
71
72    /* compare cells by contents; empty cells come before anything else */
73    a = ((PyCellObject *)a)->ob_ref;
74    b = ((PyCellObject *)b)->ob_ref;
75    if (a != NULL && b != NULL)
76        return PyObject_RichCompare(a, b, op);
77
78    result = (b == NULL) - (a == NULL);
79    switch (op) {
80    case Py_EQ:
81        v = TEST_COND(result == 0);
82        break;
83    case Py_NE:
84        v = TEST_COND(result != 0);
85        break;
86    case Py_LE:
87        v = TEST_COND(result <= 0);
88        break;
89    case Py_GE:
90        v = TEST_COND(result >= 0);
91        break;
92    case Py_LT:
93        v = TEST_COND(result < 0);
94        break;
95    case Py_GT:
96        v = TEST_COND(result > 0);
97        break;
98    default:
99        PyErr_BadArgument();
100        return NULL;
101    }
102    Py_INCREF(v);
103    return v;
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, op->ob_ref->ob_type->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 PyGetSetDef cell_getsetlist[] = {
144    {"cell_contents", (getter)cell_get_contents, NULL},
145    {NULL} /* sentinel */
146};
147
148PyTypeObject PyCell_Type = {
149    PyVarObject_HEAD_INIT(&PyType_Type, 0)
150    "cell",
151    sizeof(PyCellObject),
152    0,
153    (destructor)cell_dealloc,                   /* tp_dealloc */
154    0,                                          /* tp_print */
155    0,                                          /* tp_getattr */
156    0,                                          /* tp_setattr */
157    0,                                          /* tp_reserved */
158    (reprfunc)cell_repr,                        /* tp_repr */
159    0,                                          /* tp_as_number */
160    0,                                          /* tp_as_sequence */
161    0,                                          /* tp_as_mapping */
162    0,                                          /* tp_hash */
163    0,                                          /* tp_call */
164    0,                                          /* tp_str */
165    PyObject_GenericGetAttr,                    /* tp_getattro */
166    0,                                          /* tp_setattro */
167    0,                                          /* tp_as_buffer */
168    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
169    0,                                          /* tp_doc */
170    (traverseproc)cell_traverse,                /* tp_traverse */
171    (inquiry)cell_clear,                        /* tp_clear */
172    cell_richcompare,                           /* tp_richcompare */
173    0,                                          /* tp_weaklistoffset */
174    0,                                          /* tp_iter */
175    0,                                          /* tp_iternext */
176    0,                                          /* tp_methods */
177    0,                                          /* tp_members */
178    cell_getsetlist,                            /* tp_getset */
179};
180