mirror of
https://github.com/python/cpython.git
synced 2026-06-05 17:31:21 +00:00
222 lines
5.8 KiB
C
222 lines
5.8 KiB
C
/* 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,
|
|
};
|