1/* InterpreterID object */
2
3#include "Python.h"
4#include "pycore_abstract.h"   // _PyIndex_Check()
5#include "pycore_interp.h"     // _PyInterpreterState_LookUpID()
6#include "pycore_interpreteridobject.h"
7
8
9typedef struct interpid {
10    PyObject_HEAD
11    int64_t id;
12} interpid;
13
14static interpid *
15newinterpid(PyTypeObject *cls, int64_t id, int force)
16{
17    PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
18    if (interp == NULL) {
19        if (force) {
20            PyErr_Clear();
21        }
22        else {
23            return NULL;
24        }
25    }
26
27    if (interp != NULL) {
28        if (_PyInterpreterState_IDIncref(interp) < 0) {
29            return NULL;
30        }
31    }
32
33    interpid *self = PyObject_New(interpid, cls);
34    if (self == NULL) {
35        if (interp != NULL) {
36            _PyInterpreterState_IDDecref(interp);
37        }
38        return NULL;
39    }
40    self->id = id;
41
42    return self;
43}
44
45static int
46interp_id_converter(PyObject *arg, void *ptr)
47{
48    int64_t id;
49    if (PyObject_TypeCheck(arg, &_PyInterpreterID_Type)) {
50        id = ((interpid *)arg)->id;
51    }
52    else if (_PyIndex_Check(arg)) {
53        id = PyLong_AsLongLong(arg);
54        if (id == -1 && PyErr_Occurred()) {
55            return 0;
56        }
57        if (id < 0) {
58            PyErr_Format(PyExc_ValueError,
59                         "interpreter ID must be a non-negative int, got %R", arg);
60            return 0;
61        }
62    }
63    else {
64        PyErr_Format(PyExc_TypeError,
65                     "interpreter ID must be an int, got %.100s",
66                     Py_TYPE(arg)->tp_name);
67        return 0;
68    }
69    *(int64_t *)ptr = id;
70    return 1;
71}
72
73static PyObject *
74interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
75{
76    static char *kwlist[] = {"id", "force", NULL};
77    int64_t id;
78    int force = 0;
79    if (!PyArg_ParseTupleAndKeywords(args, kwds,
80                                     "O&|$p:InterpreterID.__init__", kwlist,
81                                     interp_id_converter, &id, &force)) {
82        return NULL;
83    }
84
85    return (PyObject *)newinterpid(cls, id, force);
86}
87
88static void
89interpid_dealloc(PyObject *v)
90{
91    int64_t id = ((interpid *)v)->id;
92    PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
93    if (interp != NULL) {
94        _PyInterpreterState_IDDecref(interp);
95    }
96    else {
97        // already deleted
98        PyErr_Clear();
99    }
100    Py_TYPE(v)->tp_free(v);
101}
102
103static PyObject *
104interpid_repr(PyObject *self)
105{
106    PyTypeObject *type = Py_TYPE(self);
107    const char *name = _PyType_Name(type);
108    interpid *id = (interpid *)self;
109    return PyUnicode_FromFormat("%s(%" PRId64 ")", name, id->id);
110}
111
112static PyObject *
113interpid_str(PyObject *self)
114{
115    interpid *id = (interpid *)self;
116    return PyUnicode_FromFormat("%" PRId64 "", id->id);
117}
118
119static PyObject *
120interpid_int(PyObject *self)
121{
122    interpid *id = (interpid *)self;
123    return PyLong_FromLongLong(id->id);
124}
125
126static PyNumberMethods interpid_as_number = {
127     0,                       /* nb_add */
128     0,                       /* nb_subtract */
129     0,                       /* nb_multiply */
130     0,                       /* nb_remainder */
131     0,                       /* nb_divmod */
132     0,                       /* nb_power */
133     0,                       /* nb_negative */
134     0,                       /* nb_positive */
135     0,                       /* nb_absolute */
136     0,                       /* nb_bool */
137     0,                       /* nb_invert */
138     0,                       /* nb_lshift */
139     0,                       /* nb_rshift */
140     0,                       /* nb_and */
141     0,                       /* nb_xor */
142     0,                       /* nb_or */
143     (unaryfunc)interpid_int, /* nb_int */
144     0,                       /* nb_reserved */
145     0,                       /* nb_float */
146
147     0,                       /* nb_inplace_add */
148     0,                       /* nb_inplace_subtract */
149     0,                       /* nb_inplace_multiply */
150     0,                       /* nb_inplace_remainder */
151     0,                       /* nb_inplace_power */
152     0,                       /* nb_inplace_lshift */
153     0,                       /* nb_inplace_rshift */
154     0,                       /* nb_inplace_and */
155     0,                       /* nb_inplace_xor */
156     0,                       /* nb_inplace_or */
157
158     0,                       /* nb_floor_divide */
159     0,                       /* nb_true_divide */
160     0,                       /* nb_inplace_floor_divide */
161     0,                       /* nb_inplace_true_divide */
162
163     (unaryfunc)interpid_int, /* nb_index */
164};
165
166static Py_hash_t
167interpid_hash(PyObject *self)
168{
169    interpid *id = (interpid *)self;
170    PyObject *obj = PyLong_FromLongLong(id->id);
171    if (obj == NULL) {
172        return -1;
173    }
174    Py_hash_t hash = PyObject_Hash(obj);
175    Py_DECREF(obj);
176    return hash;
177}
178
179static PyObject *
180interpid_richcompare(PyObject *self, PyObject *other, int op)
181{
182    if (op != Py_EQ && op != Py_NE) {
183        Py_RETURN_NOTIMPLEMENTED;
184    }
185
186    if (!PyObject_TypeCheck(self, &_PyInterpreterID_Type)) {
187        Py_RETURN_NOTIMPLEMENTED;
188    }
189
190    interpid *id = (interpid *)self;
191    int equal;
192    if (PyObject_TypeCheck(other, &_PyInterpreterID_Type)) {
193        interpid *otherid = (interpid *)other;
194        equal = (id->id == otherid->id);
195    }
196    else if (PyLong_CheckExact(other)) {
197        /* Fast path */
198        int overflow;
199        long long otherid = PyLong_AsLongLongAndOverflow(other, &overflow);
200        if (otherid == -1 && PyErr_Occurred()) {
201            return NULL;
202        }
203        equal = !overflow && (otherid >= 0) && (id->id == otherid);
204    }
205    else if (PyNumber_Check(other)) {
206        PyObject *pyid = PyLong_FromLongLong(id->id);
207        if (pyid == NULL) {
208            return NULL;
209        }
210        PyObject *res = PyObject_RichCompare(pyid, other, op);
211        Py_DECREF(pyid);
212        return res;
213    }
214    else {
215        Py_RETURN_NOTIMPLEMENTED;
216    }
217
218    if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
219        Py_RETURN_TRUE;
220    }
221    Py_RETURN_FALSE;
222}
223
224PyDoc_STRVAR(interpid_doc,
225"A interpreter ID identifies a interpreter and may be used as an int.");
226
227PyTypeObject _PyInterpreterID_Type = {
228    PyVarObject_HEAD_INIT(&PyType_Type, 0)
229    "InterpreterID",   /* tp_name */
230    sizeof(interpid),               /* tp_basicsize */
231    0,                              /* tp_itemsize */
232    (destructor)interpid_dealloc,   /* tp_dealloc */
233    0,                              /* tp_vectorcall_offset */
234    0,                              /* tp_getattr */
235    0,                              /* tp_setattr */
236    0,                              /* tp_as_async */
237    (reprfunc)interpid_repr,        /* tp_repr */
238    &interpid_as_number,            /* tp_as_number */
239    0,                              /* tp_as_sequence */
240    0,                              /* tp_as_mapping */
241    interpid_hash,                  /* tp_hash */
242    0,                              /* tp_call */
243    (reprfunc)interpid_str,         /* tp_str */
244    0,                              /* tp_getattro */
245    0,                              /* tp_setattro */
246    0,                              /* tp_as_buffer */
247    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
248    interpid_doc,                   /* tp_doc */
249    0,                              /* tp_traverse */
250    0,                              /* tp_clear */
251    interpid_richcompare,           /* tp_richcompare */
252    0,                              /* tp_weaklistoffset */
253    0,                              /* tp_iter */
254    0,                              /* tp_iternext */
255    0,                              /* tp_methods */
256    0,                              /* tp_members */
257    0,                              /* tp_getset */
258    0,                              /* tp_base */
259    0,                              /* tp_dict */
260    0,                              /* tp_descr_get */
261    0,                              /* tp_descr_set */
262    0,                              /* tp_dictoffset */
263    0,                              /* tp_init */
264    0,                              /* tp_alloc */
265    interpid_new,                   /* tp_new */
266};
267
268PyObject *_PyInterpreterID_New(int64_t id)
269{
270    return (PyObject *)newinterpid(&_PyInterpreterID_Type, id, 0);
271}
272
273PyObject *
274_PyInterpreterState_GetIDObject(PyInterpreterState *interp)
275{
276    if (_PyInterpreterState_IDInitref(interp) != 0) {
277        return NULL;
278    };
279    int64_t id = PyInterpreterState_GetID(interp);
280    if (id < 0) {
281        return NULL;
282    }
283    return (PyObject *)newinterpid(&_PyInterpreterID_Type, id, 0);
284}
285
286PyInterpreterState *
287_PyInterpreterID_LookUp(PyObject *requested_id)
288{
289    int64_t id;
290    if (!interp_id_converter(requested_id, &id)) {
291        return NULL;
292    }
293    return _PyInterpreterState_LookUpID(id);
294}
295