diff options
author | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:24:06 +0300 |
---|---|---|
committer | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:41:34 +0300 |
commit | e0e3e1717e3d33762ce61950504f9637a6e669ed (patch) | |
tree | bca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/tools/python3/src/Objects/classobject.c | |
parent | 38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff) | |
download | ydb-e0e3e1717e3d33762ce61950504f9637a6e669ed.tar.gz |
add ydb deps
Diffstat (limited to 'contrib/tools/python3/src/Objects/classobject.c')
-rw-r--r-- | contrib/tools/python3/src/Objects/classobject.c | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/contrib/tools/python3/src/Objects/classobject.c b/contrib/tools/python3/src/Objects/classobject.c new file mode 100644 index 0000000000..b9708ba0e4 --- /dev/null +++ b/contrib/tools/python3/src/Objects/classobject.c @@ -0,0 +1,545 @@ +/* Class object implementation (dead now except for methods) */ + +#include "Python.h" +#include "pycore_call.h" // _PyObject_VectorcallTstate() +#include "pycore_object.h" +#include "pycore_pyerrors.h" +#include "pycore_pystate.h" // _PyThreadState_GET() +#include "structmember.h" // PyMemberDef + +#include "clinic/classobject.c.h" + +#define TP_DESCR_GET(t) ((t)->tp_descr_get) + +/*[clinic input] +class method "PyMethodObject *" "&PyMethod_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b16e47edf6107c23]*/ + + +PyObject * +PyMethod_Function(PyObject *im) +{ + if (!PyMethod_Check(im)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyMethodObject *)im)->im_func; +} + +PyObject * +PyMethod_Self(PyObject *im) +{ + if (!PyMethod_Check(im)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyMethodObject *)im)->im_self; +} + + +static PyObject * +method_vectorcall(PyObject *method, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + assert(Py_IS_TYPE(method, &PyMethod_Type)); + + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *self = PyMethod_GET_SELF(method); + PyObject *func = PyMethod_GET_FUNCTION(method); + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + + PyObject *result; + if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET) { + /* PY_VECTORCALL_ARGUMENTS_OFFSET is set, so we are allowed to mutate the vector */ + PyObject **newargs = (PyObject**)args - 1; + nargs += 1; + PyObject *tmp = newargs[0]; + newargs[0] = self; + result = _PyObject_VectorcallTstate(tstate, func, newargs, + nargs, kwnames); + newargs[0] = tmp; + } + else { + Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + Py_ssize_t totalargs = nargs + nkwargs; + if (totalargs == 0) { + return _PyObject_VectorcallTstate(tstate, func, &self, 1, NULL); + } + + PyObject *newargs_stack[_PY_FASTCALL_SMALL_STACK]; + PyObject **newargs; + if (totalargs <= (Py_ssize_t)Py_ARRAY_LENGTH(newargs_stack) - 1) { + newargs = newargs_stack; + } + else { + newargs = PyMem_Malloc((totalargs+1) * sizeof(PyObject *)); + if (newargs == NULL) { + _PyErr_NoMemory(tstate); + return NULL; + } + } + /* use borrowed references */ + newargs[0] = self; + /* bpo-37138: since totalargs > 0, it's impossible that args is NULL. + * We need this, since calling memcpy() with a NULL pointer is + * undefined behaviour. */ + assert(args != NULL); + memcpy(newargs + 1, args, totalargs * sizeof(PyObject *)); + result = _PyObject_VectorcallTstate(tstate, func, + newargs, nargs+1, kwnames); + if (newargs != newargs_stack) { + PyMem_Free(newargs); + } + } + return result; +} + + +/* Method objects are used for bound instance methods returned by + instancename.methodname. ClassName.methodname returns an ordinary + function. +*/ + +PyObject * +PyMethod_New(PyObject *func, PyObject *self) +{ + if (self == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); + if (im == NULL) { + return NULL; + } + im->im_weakreflist = NULL; + Py_INCREF(func); + im->im_func = func; + Py_INCREF(self); + im->im_self = self; + im->vectorcall = method_vectorcall; + _PyObject_GC_TRACK(im); + return (PyObject *)im; +} + +/*[clinic input] +method.__reduce__ +[clinic start generated code]*/ + +static PyObject * +method___reduce___impl(PyMethodObject *self) +/*[clinic end generated code: output=6c04506d0fa6fdcb input=143a0bf5e96de6e8]*/ +{ + PyObject *funcself = PyMethod_GET_SELF(self); + PyObject *func = PyMethod_GET_FUNCTION(self); + PyObject *funcname = PyObject_GetAttr(func, &_Py_ID(__name__)); + if (funcname == NULL) { + return NULL; + } + return Py_BuildValue( + "N(ON)", _PyEval_GetBuiltin(&_Py_ID(getattr)), funcself, funcname); +} + +static PyMethodDef method_methods[] = { + METHOD___REDUCE___METHODDEF + {NULL, NULL} +}; + +/* Descriptors for PyMethod attributes */ + +/* im_func and im_self are stored in the PyMethod object */ + +#define MO_OFF(x) offsetof(PyMethodObject, x) + +static PyMemberDef method_memberlist[] = { + {"__func__", T_OBJECT, MO_OFF(im_func), READONLY, + "the function (or other callable) implementing a method"}, + {"__self__", T_OBJECT, MO_OFF(im_self), READONLY, + "the instance to which a method is bound"}, + {NULL} /* Sentinel */ +}; + +/* Christian Tismer argued convincingly that method attributes should + (nearly) always override function attributes. + The one exception is __doc__; there's a default __doc__ which + should only be used for the class, not for instances */ + +static PyObject * +method_get_doc(PyMethodObject *im, void *context) +{ + return PyObject_GetAttr(im->im_func, &_Py_ID(__doc__)); +} + +static PyGetSetDef method_getset[] = { + {"__doc__", (getter)method_get_doc, NULL, NULL}, + {0} +}; + +static PyObject * +method_getattro(PyObject *obj, PyObject *name) +{ + PyMethodObject *im = (PyMethodObject *)obj; + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr = NULL; + + { + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) + return NULL; + } + descr = _PyType_Lookup(tp, name); + } + + if (descr != NULL) { + descrgetfunc f = TP_DESCR_GET(Py_TYPE(descr)); + if (f != NULL) + return f(descr, obj, (PyObject *)Py_TYPE(obj)); + else { + Py_INCREF(descr); + return descr; + } + } + + return PyObject_GetAttr(im->im_func, name); +} + +/*[clinic input] +@classmethod +method.__new__ as method_new + function: object + instance: object + / + +Create a bound instance method object. +[clinic start generated code]*/ + +static PyObject * +method_new_impl(PyTypeObject *type, PyObject *function, PyObject *instance) +/*[clinic end generated code: output=d33ef4ebf702e1f7 input=4e32facc3c3108ae]*/ +{ + if (!PyCallable_Check(function)) { + PyErr_SetString(PyExc_TypeError, + "first argument must be callable"); + return NULL; + } + if (instance == NULL || instance == Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance must not be None"); + return NULL; + } + + return PyMethod_New(function, instance); +} + +static void +method_dealloc(PyMethodObject *im) +{ + _PyObject_GC_UNTRACK(im); + if (im->im_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *)im); + Py_DECREF(im->im_func); + Py_XDECREF(im->im_self); + PyObject_GC_Del(im); +} + +static PyObject * +method_richcompare(PyObject *self, PyObject *other, int op) +{ + PyMethodObject *a, *b; + PyObject *res; + int eq; + + if ((op != Py_EQ && op != Py_NE) || + !PyMethod_Check(self) || + !PyMethod_Check(other)) + { + Py_RETURN_NOTIMPLEMENTED; + } + a = (PyMethodObject *)self; + b = (PyMethodObject *)other; + eq = PyObject_RichCompareBool(a->im_func, b->im_func, Py_EQ); + if (eq == 1) { + eq = (a->im_self == b->im_self); + } + else if (eq < 0) + return NULL; + if (op == Py_EQ) + res = eq ? Py_True : Py_False; + else + res = eq ? Py_False : Py_True; + Py_INCREF(res); + return res; +} + +static PyObject * +method_repr(PyMethodObject *a) +{ + PyObject *self = a->im_self; + PyObject *func = a->im_func; + PyObject *funcname, *result; + const char *defname = "?"; + + if (_PyObject_LookupAttr(func, &_Py_ID(__qualname__), &funcname) < 0 || + (funcname == NULL && + _PyObject_LookupAttr(func, &_Py_ID(__name__), &funcname) < 0)) + { + return NULL; + } + + if (funcname != NULL && !PyUnicode_Check(funcname)) { + Py_DECREF(funcname); + funcname = NULL; + } + + /* XXX Shouldn't use repr()/%R here! */ + result = PyUnicode_FromFormat("<bound method %V of %R>", + funcname, defname, self); + + Py_XDECREF(funcname); + return result; +} + +static Py_hash_t +method_hash(PyMethodObject *a) +{ + Py_hash_t x, y; + x = _Py_HashPointer(a->im_self); + y = PyObject_Hash(a->im_func); + if (y == -1) + return -1; + x = x ^ y; + if (x == -1) + x = -2; + return x; +} + +static int +method_traverse(PyMethodObject *im, visitproc visit, void *arg) +{ + Py_VISIT(im->im_func); + Py_VISIT(im->im_self); + return 0; +} + +PyTypeObject PyMethod_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "method", + .tp_basicsize = sizeof(PyMethodObject), + .tp_dealloc = (destructor)method_dealloc, + .tp_vectorcall_offset = offsetof(PyMethodObject, vectorcall), + .tp_repr = (reprfunc)method_repr, + .tp_hash = (hashfunc)method_hash, + .tp_call = PyVectorcall_Call, + .tp_getattro = method_getattro, + .tp_setattro = PyObject_GenericSetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_HAVE_VECTORCALL, + .tp_doc = method_new__doc__, + .tp_traverse = (traverseproc)method_traverse, + .tp_richcompare = method_richcompare, + .tp_weaklistoffset = offsetof(PyMethodObject, im_weakreflist), + .tp_methods = method_methods, + .tp_members = method_memberlist, + .tp_getset = method_getset, + .tp_new = method_new, +}; + +/* ------------------------------------------------------------------------ + * instance method + */ + +/*[clinic input] +class instancemethod "PyInstanceMethodObject *" "&PyInstanceMethod_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=28c9762a9016f4d2]*/ + +PyObject * +PyInstanceMethod_New(PyObject *func) { + PyInstanceMethodObject *method; + method = PyObject_GC_New(PyInstanceMethodObject, + &PyInstanceMethod_Type); + if (method == NULL) return NULL; + Py_INCREF(func); + method->func = func; + _PyObject_GC_TRACK(method); + return (PyObject *)method; +} + +PyObject * +PyInstanceMethod_Function(PyObject *im) +{ + if (!PyInstanceMethod_Check(im)) { + PyErr_BadInternalCall(); + return NULL; + } + return PyInstanceMethod_GET_FUNCTION(im); +} + +#define IMO_OFF(x) offsetof(PyInstanceMethodObject, x) + +static PyMemberDef instancemethod_memberlist[] = { + {"__func__", T_OBJECT, IMO_OFF(func), READONLY, + "the function (or other callable) implementing a method"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +instancemethod_get_doc(PyObject *self, void *context) +{ + return PyObject_GetAttr(PyInstanceMethod_GET_FUNCTION(self), + &_Py_ID(__doc__)); +} + +static PyGetSetDef instancemethod_getset[] = { + {"__doc__", (getter)instancemethod_get_doc, NULL, NULL}, + {0} +}; + +static PyObject * +instancemethod_getattro(PyObject *self, PyObject *name) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject *descr = NULL; + + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) + return NULL; + } + descr = _PyType_Lookup(tp, name); + + if (descr != NULL) { + descrgetfunc f = TP_DESCR_GET(Py_TYPE(descr)); + if (f != NULL) + return f(descr, self, (PyObject *)Py_TYPE(self)); + else { + Py_INCREF(descr); + return descr; + } + } + + return PyObject_GetAttr(PyInstanceMethod_GET_FUNCTION(self), name); +} + +static void +instancemethod_dealloc(PyObject *self) { + _PyObject_GC_UNTRACK(self); + Py_DECREF(PyInstanceMethod_GET_FUNCTION(self)); + PyObject_GC_Del(self); +} + +static int +instancemethod_traverse(PyObject *self, visitproc visit, void *arg) { + Py_VISIT(PyInstanceMethod_GET_FUNCTION(self)); + return 0; +} + +static PyObject * +instancemethod_call(PyObject *self, PyObject *arg, PyObject *kw) +{ + return PyObject_Call(PyInstanceMethod_GET_FUNCTION(self), arg, kw); +} + +static PyObject * +instancemethod_descr_get(PyObject *descr, PyObject *obj, PyObject *type) { + PyObject *func = PyInstanceMethod_GET_FUNCTION(descr); + if (obj == NULL) { + Py_INCREF(func); + return func; + } + else + return PyMethod_New(func, obj); +} + +static PyObject * +instancemethod_richcompare(PyObject *self, PyObject *other, int op) +{ + PyInstanceMethodObject *a, *b; + PyObject *res; + int eq; + + if ((op != Py_EQ && op != Py_NE) || + !PyInstanceMethod_Check(self) || + !PyInstanceMethod_Check(other)) + { + Py_RETURN_NOTIMPLEMENTED; + } + a = (PyInstanceMethodObject *)self; + b = (PyInstanceMethodObject *)other; + eq = PyObject_RichCompareBool(a->func, b->func, Py_EQ); + if (eq < 0) + return NULL; + if (op == Py_EQ) + res = eq ? Py_True : Py_False; + else + res = eq ? Py_False : Py_True; + Py_INCREF(res); + return res; +} + +static PyObject * +instancemethod_repr(PyObject *self) +{ + PyObject *func = PyInstanceMethod_Function(self); + PyObject *funcname, *result; + const char *defname = "?"; + + if (func == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + if (_PyObject_LookupAttr(func, &_Py_ID(__name__), &funcname) < 0) { + return NULL; + } + if (funcname != NULL && !PyUnicode_Check(funcname)) { + Py_DECREF(funcname); + funcname = NULL; + } + + result = PyUnicode_FromFormat("<instancemethod %V at %p>", + funcname, defname, self); + + Py_XDECREF(funcname); + return result; +} + +/*[clinic input] +@classmethod +instancemethod.__new__ as instancemethod_new + function: object + / + +Bind a function to a class. +[clinic start generated code]*/ + +static PyObject * +instancemethod_new_impl(PyTypeObject *type, PyObject *function) +/*[clinic end generated code: output=5e0397b2bdb750be input=cfc54e8b973664a8]*/ +{ + if (!PyCallable_Check(function)) { + PyErr_SetString(PyExc_TypeError, + "first argument must be callable"); + return NULL; + } + + return PyInstanceMethod_New(function); +} + +PyTypeObject PyInstanceMethod_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "instancemethod", + .tp_basicsize = sizeof(PyInstanceMethodObject), + .tp_dealloc = instancemethod_dealloc, + .tp_repr = (reprfunc)instancemethod_repr, + .tp_call = instancemethod_call, + .tp_getattro = instancemethod_getattro, + .tp_setattro = PyObject_GenericSetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_doc = instancemethod_new__doc__, + .tp_traverse = instancemethod_traverse, + .tp_richcompare = instancemethod_richcompare, + .tp_members = instancemethod_memberlist, + .tp_getset = instancemethod_getset, + .tp_descr_get = instancemethod_descr_get, + .tp_new = instancemethod_new, +}; |