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
54static int
55cell_compare(PyCellObject *a, PyCellObject *b)
56{
57    /* Py3K warning for comparisons  */
58    if (PyErr_WarnPy3k("cell comparisons not supported in 3.x",
59                       1) < 0) {
60        return -2;
61    }
62
63    if (a->ob_ref == NULL) {
64        if (b->ob_ref == NULL)
65            return 0;
66        return -1;
67    } else if (b->ob_ref == NULL)
68        return 1;
69    return PyObject_Compare(a->ob_ref, b->ob_ref);
70}
71
72static PyObject *
73cell_repr(PyCellObject *op)
74{
75    if (op->ob_ref == NULL)
76        return PyString_FromFormat("<cell at %p: empty>", op);
77
78    return PyString_FromFormat("<cell at %p: %.80s object at %p>",
79                               op, op->ob_ref->ob_type->tp_name,
80                               op->ob_ref);
81}
82
83static int
84cell_traverse(PyCellObject *op, visitproc visit, void *arg)
85{
86    Py_VISIT(op->ob_ref);
87    return 0;
88}
89
90static int
91cell_clear(PyCellObject *op)
92{
93    Py_CLEAR(op->ob_ref);
94    return 0;
95}
96
97static PyObject *
98cell_get_contents(PyCellObject *op, void *closure)
99{
100    if (op->ob_ref == NULL)
101    {
102        PyErr_SetString(PyExc_ValueError, "Cell is empty");
103        return NULL;
104    }
105    Py_INCREF(op->ob_ref);
106    return op->ob_ref;
107}
108
109static PyGetSetDef cell_getsetlist[] = {
110    {"cell_contents", (getter)cell_get_contents, NULL},
111    {NULL} /* sentinel */
112};
113
114PyTypeObject PyCell_Type = {
115    PyVarObject_HEAD_INIT(&PyType_Type, 0)
116    "cell",
117    sizeof(PyCellObject),
118    0,
119    (destructor)cell_dealloc,                   /* tp_dealloc */
120    0,                                          /* tp_print */
121    0,                                          /* tp_getattr */
122    0,                                          /* tp_setattr */
123    (cmpfunc)cell_compare,                      /* tp_compare */
124    (reprfunc)cell_repr,                        /* tp_repr */
125    0,                                          /* tp_as_number */
126    0,                                          /* tp_as_sequence */
127    0,                                          /* tp_as_mapping */
128    0,                                          /* tp_hash */
129    0,                                          /* tp_call */
130    0,                                          /* tp_str */
131    PyObject_GenericGetAttr,                    /* tp_getattro */
132    0,                                          /* tp_setattro */
133    0,                                          /* tp_as_buffer */
134    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
135    0,                                          /* tp_doc */
136    (traverseproc)cell_traverse,                /* tp_traverse */
137    (inquiry)cell_clear,                        /* tp_clear */
138    0,                                          /* tp_richcompare */
139    0,                                          /* tp_weaklistoffset */
140    0,                                          /* tp_iter */
141    0,                                          /* tp_iternext */
142    0,                                          /* tp_methods */
143    0,                                          /* tp_members */
144    cell_getsetlist,                            /* tp_getset */
145};
146