| /* Sentinel object implementation */ | |
| #include "Python.h" | |
| #include "descrobject.h" // PyMemberDef | |
| #include "pycore_ceval.h" // _PyThreadState_GET() | |
| #include "pycore_interpframe.h" // _PyFrame_IsIncomplete() | |
| #include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK() | |
| #include "pycore_stackref.h" // PyStackRef_AsPyObjectBorrow() | |
| #include "pycore_tuple.h" // _PyTuple_FromPair | |
| #include "pycore_typeobject.h" // _Py_BaseObject_RichCompare() | |
| #include "pycore_unionobject.h" // _Py_union_type_or() | |
| typedef struct { | |
| PyObject_HEAD | |
| PyObject *name; | |
| PyObject *module; | |
| PyObject *repr; | |
| } sentinelobject; | |
| #define sentinelobject_CAST(op) \ | |
| (assert(PySentinel_Check(op)), _Py_CAST(sentinelobject *, (op))) | |
| /*[clinic input] | |
| class sentinel "sentinelobject *" "&PySentinel_Type" | |
| [clinic start generated code]*/ | |
| /*[clinic end generated code: output=da39a3ee5e6b4b0d input=8b88f8268d3b5775]*/ | |
| #include "clinic/sentinelobject.c.h" | |
| static PyObject * | |
| caller(void) | |
| { | |
| _PyInterpreterFrame *f = _PyThreadState_GET()->current_frame; | |
| if (f == NULL || PyStackRef_IsNull(f->f_funcobj)) { | |
| assert(!PyErr_Occurred()); | |
| Py_RETURN_NONE; | |
| } | |
| PyFunctionObject *func = _PyFrame_GetFunction(f); | |
| assert(PyFunction_Check(func)); | |
| PyObject *r = PyFunction_GetModule((PyObject *)func); | |
| if (!r) { | |
| assert(!PyErr_Occurred()); | |
| Py_RETURN_NONE; | |
| } | |
| return Py_NewRef(r); | |
| } | |
| static PyObject * | |
| sentinel_new_with_module(PyTypeObject *type, PyObject *name, PyObject *module, PyObject *repr) | |
| { | |
| assert(PyUnicode_Check(name)); | |
| sentinelobject *self = PyObject_GC_New(sentinelobject, type); | |
| if (self == NULL) { | |
| return NULL; | |
| } | |
| self->name = Py_NewRef(name); | |
| self->module = Py_NewRef(module); | |
| self->repr = Py_XNewRef(repr); | |
| _PyObject_GC_TRACK(self); | |
| return (PyObject *)self; | |
| } | |
| /*[clinic input] | |
| @classmethod | |
| sentinel.__new__ as sentinel_new | |
| name: object(subclass_of='&PyUnicode_Type') | |
| / | |
| * | |
| repr: object = None | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| sentinel_new_impl(PyTypeObject *type, PyObject *name, PyObject *repr) | |
| /*[clinic end generated code: output=1eb7fab52e57d8c8 input=28cab6c468997b35]*/ | |
| { | |
| if (repr == Py_None) { | |
| repr = NULL; | |
| } | |
| else if (!PyUnicode_Check(repr)) { | |
| _PyArg_BadArgument("sentinel", "argument 'repr'", "str or None", repr); | |
| return NULL; | |
| } | |
| PyObject *module = caller(); | |
| PyObject *self = sentinel_new_with_module(type, name, module, repr); | |
| Py_DECREF(module); | |
| return self; | |
| } | |
| PyObject * | |
| PySentinel_New(const char *name, const char *module_name, const char *repr) | |
| { | |
| PyObject *name_obj = PyUnicode_FromString(name); | |
| if (name_obj == NULL) { | |
| return NULL; | |
| } | |
| PyObject *repr_obj = NULL; | |
| if (repr != NULL) { | |
| repr_obj = PyUnicode_FromString(repr); | |
| if (repr_obj == NULL) { | |
| Py_DECREF(name_obj); | |
| return NULL; | |
| } | |
| } | |
| PyObject *module_obj = module_name == NULL | |
| ? Py_None | |
| : PyUnicode_FromString(module_name); | |
| if (module_obj == NULL) { | |
| Py_DECREF(name_obj); | |
| Py_XDECREF(repr_obj); | |
| return NULL; | |
| } | |
| PyObject *sentinel = sentinel_new_with_module( | |
| &PySentinel_Type, name_obj, module_obj, repr_obj); | |
| Py_DECREF(module_obj); | |
| Py_DECREF(name_obj); | |
| Py_XDECREF(repr_obj); | |
| return sentinel; | |
| } | |
| static int | |
| sentinel_clear(PyObject *op) | |
| { | |
| sentinelobject *self = sentinelobject_CAST(op); | |
| Py_CLEAR(self->name); | |
| Py_CLEAR(self->module); | |
| Py_CLEAR(self->repr); | |
| return 0; | |
| } | |
| static void | |
| sentinel_dealloc(PyObject *op) | |
| { | |
| _PyObject_GC_UNTRACK(op); | |
| (void)sentinel_clear(op); | |
| Py_TYPE(op)->tp_free(op); | |
| } | |
| static int | |
| sentinel_traverse(PyObject *op, visitproc visit, void *arg) | |
| { | |
| sentinelobject *self = sentinelobject_CAST(op); | |
| Py_VISIT(self->name); | |
| Py_VISIT(self->module); | |
| Py_VISIT(self->repr); | |
| return 0; | |
| } | |
| static PyObject * | |
| sentinel_repr(PyObject *op) | |
| { | |
| sentinelobject *self = sentinelobject_CAST(op); | |
| if (self->repr != NULL) { | |
| return Py_NewRef(self->repr); | |
| } | |
| return Py_NewRef(self->name); | |
| } | |
| static PyObject * | |
| sentinel_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) | |
| { | |
| return Py_NewRef(self); | |
| } | |
| static PyObject * | |
| sentinel_deepcopy(PyObject *self, PyObject *Py_UNUSED(memo)) | |
| { | |
| return Py_NewRef(self); | |
| } | |
| static PyObject * | |
| sentinel_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) | |
| { | |
| sentinelobject *self = sentinelobject_CAST(op); | |
| return Py_NewRef(self->name); | |
| } | |
| static PyMethodDef sentinel_methods[] = { | |
| {"__copy__", sentinel_copy, METH_NOARGS, NULL}, | |
| {"__deepcopy__", sentinel_deepcopy, METH_O, NULL}, | |
| {"__reduce__", sentinel_reduce, METH_NOARGS, NULL}, | |
| {NULL, NULL} | |
| }; | |
| static PyMemberDef sentinel_members[] = { | |
| {"__name__", Py_T_OBJECT_EX, offsetof(sentinelobject, name), Py_READONLY}, | |
| {"__module__", Py_T_OBJECT_EX, offsetof(sentinelobject, module), 0}, | |
| {NULL} | |
| }; | |
| static PyNumberMethods sentinel_as_number = { | |
| .nb_or = _Py_union_type_or, | |
| }; | |
| PyDoc_STRVAR(sentinel_doc, | |
| "sentinel(name, /, *, repr=None)\n" | |
| "--\n\n" | |
| "Create a unique sentinel object with the given name."); | |
| PyTypeObject PySentinel_Type = { | |
| PyVarObject_HEAD_INIT(&PyType_Type, 0) | |
| .tp_name = "sentinel", | |
| .tp_basicsize = sizeof(sentinelobject), | |
| .tp_dealloc = sentinel_dealloc, | |
| .tp_repr = sentinel_repr, | |
| .tp_as_number = &sentinel_as_number, | |
| .tp_hash = PyObject_GenericHash, | |
| .tp_getattro = PyObject_GenericGetAttr, | |
| .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | |
| | Py_TPFLAGS_HAVE_GC, | |
| .tp_doc = sentinel_doc, | |
| .tp_traverse = sentinel_traverse, | |
| .tp_clear = sentinel_clear, | |
| .tp_richcompare = _Py_BaseObject_RichCompare, | |
| .tp_methods = sentinel_methods, | |
| .tp_members = sentinel_members, | |
| .tp_new = sentinel_new, | |
| .tp_free = PyObject_GC_Del, | |
| }; |