| /* InterpreterID object */ | 
 |  | 
 | #include "Python.h" | 
 | #include "internal/pycore_pystate.h" | 
 | #include "interpreteridobject.h" | 
 |  | 
 |  | 
 | int64_t | 
 | _Py_CoerceID(PyObject *orig) | 
 | { | 
 |     PyObject *pyid = PyNumber_Long(orig); | 
 |     if (pyid == NULL) { | 
 |         if (PyErr_ExceptionMatches(PyExc_TypeError)) { | 
 |             PyErr_Format(PyExc_TypeError, | 
 |                          "'id' must be a non-negative int, got %R", orig); | 
 |         } | 
 |         else { | 
 |             PyErr_Format(PyExc_ValueError, | 
 |                          "'id' must be a non-negative int, got %R", orig); | 
 |         } | 
 |         return -1; | 
 |     } | 
 |     int64_t id = PyLong_AsLongLong(pyid); | 
 |     Py_DECREF(pyid); | 
 |     if (id == -1 && PyErr_Occurred() != NULL) { | 
 |         if (!PyErr_ExceptionMatches(PyExc_OverflowError)) { | 
 |             PyErr_Format(PyExc_ValueError, | 
 |                          "'id' must be a non-negative int, got %R", orig); | 
 |         } | 
 |         return -1; | 
 |     } | 
 |     if (id < 0) { | 
 |         PyErr_Format(PyExc_ValueError, | 
 |                      "'id' must be a non-negative int, got %R", orig); | 
 |         return -1; | 
 |     } | 
 |     return id; | 
 | } | 
 |  | 
 | typedef struct interpid { | 
 |     PyObject_HEAD | 
 |     int64_t id; | 
 | } interpid; | 
 |  | 
 | static interpid * | 
 | newinterpid(PyTypeObject *cls, int64_t id, int force) | 
 | { | 
 |     PyInterpreterState *interp = _PyInterpreterState_LookUpID(id); | 
 |     if (interp == NULL) { | 
 |         if (force) { | 
 |             PyErr_Clear(); | 
 |         } | 
 |         else { | 
 |             return NULL; | 
 |         } | 
 |     } | 
 |  | 
 |     interpid *self = PyObject_New(interpid, cls); | 
 |     if (self == NULL) { | 
 |         return NULL; | 
 |     } | 
 |     self->id = id; | 
 |  | 
 |     if (interp != NULL) { | 
 |         _PyInterpreterState_IDIncref(interp); | 
 |     } | 
 |     return self; | 
 | } | 
 |  | 
 | static PyObject * | 
 | interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds) | 
 | { | 
 |     static char *kwlist[] = {"id", "force", NULL}; | 
 |     PyObject *idobj; | 
 |     int force = 0; | 
 |     if (!PyArg_ParseTupleAndKeywords(args, kwds, | 
 |                                      "O|$p:InterpreterID.__init__", kwlist, | 
 |                                      &idobj, &force)) { | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     // Coerce and check the ID. | 
 |     int64_t id; | 
 |     if (PyObject_TypeCheck(idobj, &_PyInterpreterID_Type)) { | 
 |         id = ((interpid *)idobj)->id; | 
 |     } | 
 |     else { | 
 |         id = _Py_CoerceID(idobj); | 
 |         if (id < 0) { | 
 |             return NULL; | 
 |         } | 
 |     } | 
 |  | 
 |     return (PyObject *)newinterpid(cls, id, force); | 
 | } | 
 |  | 
 | static void | 
 | interpid_dealloc(PyObject *v) | 
 | { | 
 |     int64_t id = ((interpid *)v)->id; | 
 |     PyInterpreterState *interp = _PyInterpreterState_LookUpID(id); | 
 |     if (interp != NULL) { | 
 |         _PyInterpreterState_IDDecref(interp); | 
 |     } | 
 |     else { | 
 |         // already deleted | 
 |         PyErr_Clear(); | 
 |     } | 
 |     Py_TYPE(v)->tp_free(v); | 
 | } | 
 |  | 
 | static PyObject * | 
 | interpid_repr(PyObject *self) | 
 | { | 
 |     PyTypeObject *type = Py_TYPE(self); | 
 |     const char *name = _PyType_Name(type); | 
 |     interpid *id = (interpid *)self; | 
 |     return PyUnicode_FromFormat("%s(%" PRId64 ")", name, id->id); | 
 | } | 
 |  | 
 | static PyObject * | 
 | interpid_str(PyObject *self) | 
 | { | 
 |     interpid *id = (interpid *)self; | 
 |     return PyUnicode_FromFormat("%" PRId64 "", id->id); | 
 | } | 
 |  | 
 | static PyObject * | 
 | interpid_int(PyObject *self) | 
 | { | 
 |     interpid *id = (interpid *)self; | 
 |     return PyLong_FromLongLong(id->id); | 
 | } | 
 |  | 
 | static PyNumberMethods interpid_as_number = { | 
 |      0,                       /* nb_add */ | 
 |      0,                       /* nb_subtract */ | 
 |      0,                       /* nb_multiply */ | 
 |      0,                       /* nb_remainder */ | 
 |      0,                       /* nb_divmod */ | 
 |      0,                       /* nb_power */ | 
 |      0,                       /* nb_negative */ | 
 |      0,                       /* nb_positive */ | 
 |      0,                       /* nb_absolute */ | 
 |      0,                       /* nb_bool */ | 
 |      0,                       /* nb_invert */ | 
 |      0,                       /* nb_lshift */ | 
 |      0,                       /* nb_rshift */ | 
 |      0,                       /* nb_and */ | 
 |      0,                       /* nb_xor */ | 
 |      0,                       /* nb_or */ | 
 |      (unaryfunc)interpid_int, /* nb_int */ | 
 |      0,                       /* nb_reserved */ | 
 |      0,                       /* nb_float */ | 
 |  | 
 |      0,                       /* nb_inplace_add */ | 
 |      0,                       /* nb_inplace_subtract */ | 
 |      0,                       /* nb_inplace_multiply */ | 
 |      0,                       /* nb_inplace_remainder */ | 
 |      0,                       /* nb_inplace_power */ | 
 |      0,                       /* nb_inplace_lshift */ | 
 |      0,                       /* nb_inplace_rshift */ | 
 |      0,                       /* nb_inplace_and */ | 
 |      0,                       /* nb_inplace_xor */ | 
 |      0,                       /* nb_inplace_or */ | 
 |  | 
 |      0,                       /* nb_floor_divide */ | 
 |      0,                       /* nb_true_divide */ | 
 |      0,                       /* nb_inplace_floor_divide */ | 
 |      0,                       /* nb_inplace_true_divide */ | 
 |  | 
 |      (unaryfunc)interpid_int, /* nb_index */ | 
 | }; | 
 |  | 
 | static Py_hash_t | 
 | interpid_hash(PyObject *self) | 
 | { | 
 |     interpid *id = (interpid *)self; | 
 |     PyObject *obj = PyLong_FromLongLong(id->id); | 
 |     if (obj == NULL) { | 
 |         return -1; | 
 |     } | 
 |     Py_hash_t hash = PyObject_Hash(obj); | 
 |     Py_DECREF(obj); | 
 |     return hash; | 
 | } | 
 |  | 
 | static PyObject * | 
 | interpid_richcompare(PyObject *self, PyObject *other, int op) | 
 | { | 
 |     if (op != Py_EQ && op != Py_NE) { | 
 |         Py_RETURN_NOTIMPLEMENTED; | 
 |     } | 
 |  | 
 |     if (!PyObject_TypeCheck(self, &_PyInterpreterID_Type)) { | 
 |         Py_RETURN_NOTIMPLEMENTED; | 
 |     } | 
 |  | 
 |     interpid *id = (interpid *)self; | 
 |     int equal; | 
 |     if (PyObject_TypeCheck(other, &_PyInterpreterID_Type)) { | 
 |         interpid *otherid = (interpid *)other; | 
 |         equal = (id->id == otherid->id); | 
 |     } | 
 |     else { | 
 |         other = PyNumber_Long(other); | 
 |         if (other == NULL) { | 
 |             PyErr_Clear(); | 
 |             Py_RETURN_NOTIMPLEMENTED; | 
 |         } | 
 |         int64_t otherid = PyLong_AsLongLong(other); | 
 |         Py_DECREF(other); | 
 |         if (otherid == -1 && PyErr_Occurred() != NULL) { | 
 |             return NULL; | 
 |         } | 
 |         if (otherid < 0) { | 
 |             equal = 0; | 
 |         } | 
 |         else { | 
 |             equal = (id->id == otherid); | 
 |         } | 
 |     } | 
 |  | 
 |     if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) { | 
 |         Py_RETURN_TRUE; | 
 |     } | 
 |     Py_RETURN_FALSE; | 
 | } | 
 |  | 
 | PyDoc_STRVAR(interpid_doc, | 
 | "A interpreter ID identifies a interpreter and may be used as an int."); | 
 |  | 
 | PyTypeObject _PyInterpreterID_Type = { | 
 |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | 
 |     "InterpreterID",   /* tp_name */ | 
 |     sizeof(interpid),               /* tp_basicsize */ | 
 |     0,                              /* tp_itemsize */ | 
 |     (destructor)interpid_dealloc,   /* tp_dealloc */ | 
 |     0,                              /* tp_vectorcall_offset */ | 
 |     0,                              /* tp_getattr */ | 
 |     0,                              /* tp_setattr */ | 
 |     0,                              /* tp_as_async */ | 
 |     (reprfunc)interpid_repr,        /* tp_repr */ | 
 |     &interpid_as_number,            /* tp_as_number */ | 
 |     0,                              /* tp_as_sequence */ | 
 |     0,                              /* tp_as_mapping */ | 
 |     interpid_hash,                  /* tp_hash */ | 
 |     0,                              /* tp_call */ | 
 |     (reprfunc)interpid_str,         /* tp_str */ | 
 |     0,                              /* tp_getattro */ | 
 |     0,                              /* tp_setattro */ | 
 |     0,                              /* tp_as_buffer */ | 
 |     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | | 
 |         Py_TPFLAGS_LONG_SUBCLASS,   /* tp_flags */ | 
 |     interpid_doc,                   /* tp_doc */ | 
 |     0,                              /* tp_traverse */ | 
 |     0,                              /* tp_clear */ | 
 |     interpid_richcompare,           /* tp_richcompare */ | 
 |     0,                              /* tp_weaklistoffset */ | 
 |     0,                              /* tp_iter */ | 
 |     0,                              /* tp_iternext */ | 
 |     0,                              /* tp_methods */ | 
 |     0,                              /* tp_members */ | 
 |     0,                              /* tp_getset */ | 
 |     &PyLong_Type,                   /* tp_base */ | 
 |     0,                              /* tp_dict */ | 
 |     0,                              /* tp_descr_get */ | 
 |     0,                              /* tp_descr_set */ | 
 |     0,                              /* tp_dictoffset */ | 
 |     0,                              /* tp_init */ | 
 |     0,                              /* tp_alloc */ | 
 |     interpid_new,                   /* tp_new */ | 
 | }; | 
 |  | 
 | PyObject *_PyInterpreterID_New(int64_t id) | 
 | { | 
 |     return (PyObject *)newinterpid(&_PyInterpreterID_Type, id, 0); | 
 | } | 
 |  | 
 | PyObject * | 
 | _PyInterpreterState_GetIDObject(PyInterpreterState *interp) | 
 | { | 
 |     if (_PyInterpreterState_IDInitref(interp) != 0) { | 
 |         return NULL; | 
 |     }; | 
 |     PY_INT64_T id = PyInterpreterState_GetID(interp); | 
 |     if (id < 0) { | 
 |         return NULL; | 
 |     } | 
 |     return (PyObject *)newinterpid(&_PyInterpreterID_Type, id, 0); | 
 | } | 
 |  | 
 | PyInterpreterState * | 
 | _PyInterpreterID_LookUp(PyObject *requested_id) | 
 | { | 
 |     int64_t id; | 
 |     if (PyObject_TypeCheck(requested_id, &_PyInterpreterID_Type)) { | 
 |         id = ((interpid *)requested_id)->id; | 
 |     } | 
 |     else { | 
 |         id = PyLong_AsLongLong(requested_id); | 
 |         if (id == -1 && PyErr_Occurred() != NULL) { | 
 |             return NULL; | 
 |         } | 
 |         assert(id <= INT64_MAX); | 
 |     } | 
 |     return _PyInterpreterState_LookUpID(id); | 
 | } |