mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
Merge of descr-branch back into trunk.
This commit is contained in:
parent
52d55a3926
commit
6d6c1a35e0
57 changed files with 6923 additions and 1309 deletions
|
@ -1588,6 +1588,24 @@ PyObject_CallObject(PyObject *o, PyObject *a)
|
|||
return r;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw)
|
||||
{
|
||||
ternaryfunc call;
|
||||
|
||||
if ((call = func->ob_type->tp_call) != NULL) {
|
||||
PyObject *result = (*call)(func, arg, kw);
|
||||
if (result == NULL && !PyErr_Occurred())
|
||||
PyErr_SetString(
|
||||
PyExc_SystemError,
|
||||
"NULL result without error in PyObject_Call");
|
||||
return result;
|
||||
}
|
||||
PyErr_Format(PyExc_TypeError, "object is not callable: %s",
|
||||
PyString_AS_STRING(PyObject_Repr(func)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyObject_CallFunction(PyObject *callable, char *format, ...)
|
||||
{
|
||||
|
@ -1746,7 +1764,7 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
|
|||
}
|
||||
}
|
||||
else if (PyType_Check(cls)) {
|
||||
retval = ((PyObject *)(inst->ob_type) == cls);
|
||||
retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls);
|
||||
}
|
||||
else if (!PyInstance_Check(inst)) {
|
||||
if (__class__ == NULL) {
|
||||
|
|
|
@ -537,21 +537,21 @@ PyTypeObject PyBuffer_Type = {
|
|||
"buffer",
|
||||
sizeof(PyBufferObject),
|
||||
0,
|
||||
(destructor)buffer_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
(cmpfunc)buffer_compare, /*tp_compare*/
|
||||
(reprfunc)buffer_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&buffer_as_sequence, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
(hashfunc)buffer_hash, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
(reprfunc)buffer_str, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
&buffer_as_buffer, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
0, /*tp_doc*/
|
||||
(destructor)buffer_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
(cmpfunc)buffer_compare, /* tp_compare */
|
||||
(reprfunc)buffer_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
&buffer_as_sequence, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)buffer_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
(reprfunc)buffer_str, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&buffer_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
};
|
||||
|
|
|
@ -106,7 +106,7 @@ PyTypeObject PyCell_Type = {
|
|||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
|
|
|
@ -36,12 +36,12 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
|
|||
return NULL;
|
||||
}
|
||||
if (name == NULL || !PyString_Check(name)) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"PyClass_New: name must be a string");
|
||||
return NULL;
|
||||
}
|
||||
if (dict == NULL || !PyDict_Check(dict)) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"PyClass_New: dict must be a dictionary");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -67,14 +67,14 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
|
|||
else {
|
||||
int i;
|
||||
if (!PyTuple_Check(bases)) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"PyClass_New: bases must be a tuple");
|
||||
return NULL;
|
||||
}
|
||||
i = PyTuple_Size(bases);
|
||||
while (--i >= 0) {
|
||||
if (!PyClass_Check(PyTuple_GetItem(bases, i))) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"PyClass_New: base must be a class");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -106,6 +106,18 @@ PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
|
|||
return (PyObject *) op;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
class_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *name, *bases, *dict;
|
||||
static char *kwlist[] = {"name", "bases", "dict", 0};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "SOO", kwlist,
|
||||
&name, &bases, &dict))
|
||||
return NULL;
|
||||
return PyClass_New(bases, dict, name);
|
||||
}
|
||||
|
||||
/* Class methods */
|
||||
|
||||
static void
|
||||
|
@ -149,6 +161,8 @@ class_getattr(register PyClassObject *op, PyObject *name)
|
|||
register PyObject *v;
|
||||
register char *sname = PyString_AsString(name);
|
||||
PyClassObject *class;
|
||||
descrgetfunc f;
|
||||
|
||||
if (sname[0] == '_' && sname[1] == '_') {
|
||||
if (strcmp(sname, "__dict__") == 0) {
|
||||
if (PyEval_GetRestricted()) {
|
||||
|
@ -186,6 +200,11 @@ class_getattr(register PyClassObject *op, PyObject *name)
|
|||
Py_DECREF(v);
|
||||
v = w;
|
||||
}
|
||||
f = v->ob_type->tp_descr_get;
|
||||
if (f == NULL)
|
||||
Py_INCREF(v);
|
||||
else
|
||||
v = f(v, (PyObject *)NULL, (PyObject *)op);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -396,7 +415,7 @@ PyTypeObject PyClass_Type = {
|
|||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
PyInstance_New, /* tp_call */
|
||||
(reprfunc)class_str, /* tp_str */
|
||||
(getattrofunc)class_getattr, /* tp_getattro */
|
||||
(setattrofunc)class_setattr, /* tp_setattro */
|
||||
|
@ -404,6 +423,22 @@ PyTypeObject PyClass_Type = {
|
|||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)class_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
class_new, /* tp_new */
|
||||
};
|
||||
|
||||
int
|
||||
|
@ -531,7 +566,7 @@ instance_dealloc(register PyInstanceObject *inst)
|
|||
/* compensate for boost in _Py_NewReference; note that
|
||||
* _Py_RefTotal was also boosted; we'll knock that down later.
|
||||
*/
|
||||
inst->ob_type->tp_alloc--;
|
||||
inst->ob_type->tp_allocs--;
|
||||
#endif
|
||||
#else /* !Py_TRACE_REFS */
|
||||
/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
|
||||
|
@ -564,7 +599,7 @@ instance_dealloc(register PyInstanceObject *inst)
|
|||
#endif
|
||||
if (--inst->ob_refcnt > 0) {
|
||||
#ifdef COUNT_ALLOCS
|
||||
inst->ob_type->tp_free--;
|
||||
inst->ob_type->tp_frees--;
|
||||
#endif
|
||||
return; /* __del__ added a reference; don't delete now */
|
||||
}
|
||||
|
@ -572,7 +607,7 @@ instance_dealloc(register PyInstanceObject *inst)
|
|||
_Py_ForgetReference((PyObject *)inst);
|
||||
#ifdef COUNT_ALLOCS
|
||||
/* compensate for increment in _Py_ForgetReference */
|
||||
inst->ob_type->tp_free--;
|
||||
inst->ob_type->tp_frees--;
|
||||
#endif
|
||||
#ifndef WITH_CYCLE_GC
|
||||
inst->ob_type = NULL;
|
||||
|
@ -619,6 +654,8 @@ instance_getattr2(register PyInstanceObject *inst, PyObject *name)
|
|||
{
|
||||
register PyObject *v;
|
||||
PyClassObject *class;
|
||||
descrgetfunc f;
|
||||
|
||||
class = NULL;
|
||||
v = PyDict_GetItem(inst->in_dict, name);
|
||||
if (v == NULL) {
|
||||
|
@ -628,17 +665,20 @@ instance_getattr2(register PyInstanceObject *inst, PyObject *name)
|
|||
}
|
||||
Py_INCREF(v);
|
||||
if (class != NULL) {
|
||||
if (PyFunction_Check(v)) {
|
||||
PyObject *w = PyMethod_New(v, (PyObject *)inst,
|
||||
(PyObject *)class);
|
||||
f = v->ob_type->tp_descr_get;
|
||||
if (f != NULL) {
|
||||
PyObject *w = f(v, (PyObject *)inst,
|
||||
(PyObject *)(inst->in_class));
|
||||
Py_DECREF(v);
|
||||
v = w;
|
||||
}
|
||||
else if (PyMethod_Check(v)) {
|
||||
PyObject *im_class = PyMethod_Class(v);
|
||||
/* XXX This should be a tp_descr_get slot of
|
||||
PyMethodObjects */
|
||||
PyObject *im_class = PyMethod_GET_CLASS(v);
|
||||
/* Only if classes are compatible */
|
||||
if (PyClass_IsSubclass((PyObject *)class, im_class)) {
|
||||
PyObject *im_func = PyMethod_Function(v);
|
||||
PyObject *im_func = PyMethod_GET_FUNCTION(v);
|
||||
PyObject *w = PyMethod_New(im_func,
|
||||
(PyObject *)inst, im_class);
|
||||
Py_DECREF(v);
|
||||
|
@ -1814,6 +1854,23 @@ instance_iternext(PyInstanceObject *self)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
instance_call(PyObject *func, PyObject *arg, PyObject *kw)
|
||||
{
|
||||
PyObject *res, *call = PyObject_GetAttrString(func, "__call__");
|
||||
if (call == NULL) {
|
||||
PyInstanceObject *inst = (PyInstanceObject*) func;
|
||||
PyErr_Clear();
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"%.200s instance has no __call__ method",
|
||||
PyString_AsString(inst->in_class->cl_name));
|
||||
return NULL;
|
||||
}
|
||||
res = PyObject_Call(call, arg, kw);
|
||||
Py_DECREF(call);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static PyNumberMethods instance_as_number = {
|
||||
(binaryfunc)instance_add, /* nb_add */
|
||||
|
@ -1868,7 +1925,7 @@ PyTypeObject PyInstance_Type = {
|
|||
&instance_as_sequence, /* tp_as_sequence */
|
||||
&instance_as_mapping, /* tp_as_mapping */
|
||||
(hashfunc)instance_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
instance_call, /* tp_call */
|
||||
(reprfunc)instance_str, /* tp_str */
|
||||
(getattrofunc)instance_getattr, /* tp_getattro */
|
||||
(setattrofunc)instance_setattr, /* tp_setattro */
|
||||
|
@ -1921,36 +1978,6 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *class)
|
|||
return (PyObject *)im;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyMethod_Function(register PyObject *im)
|
||||
{
|
||||
if (!PyMethod_Check(im)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyMethodObject *)im)->im_func;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyMethod_Self(register PyObject *im)
|
||||
{
|
||||
if (!PyMethod_Check(im)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyMethodObject *)im)->im_self;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyMethod_Class(register PyObject *im)
|
||||
{
|
||||
if (!PyMethod_Check(im)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyMethodObject *)im)->im_class;
|
||||
}
|
||||
|
||||
/* Class method methods */
|
||||
|
||||
#define OFF(x) offsetof(PyMethodObject, x)
|
||||
|
@ -2028,43 +2055,52 @@ instancemethod_compare(PyMethodObject *a, PyMethodObject *b)
|
|||
static PyObject *
|
||||
instancemethod_repr(PyMethodObject *a)
|
||||
{
|
||||
char buf[240];
|
||||
PyInstanceObject *self = (PyInstanceObject *)(a->im_self);
|
||||
char buffer[240];
|
||||
PyObject *self = a->im_self;
|
||||
PyObject *func = a->im_func;
|
||||
PyClassObject *class = (PyClassObject *)(a->im_class);
|
||||
PyObject *fclassname, *iclassname, *funcname;
|
||||
char *fcname, *icname, *fname;
|
||||
fclassname = class->cl_name;
|
||||
if (PyFunction_Check(func)) {
|
||||
funcname = ((PyFunctionObject *)func)->func_name;
|
||||
Py_INCREF(funcname);
|
||||
PyObject *klass = a->im_class;
|
||||
PyObject *funcname = NULL, *klassname = NULL, *result = NULL;
|
||||
char *sfuncname = "?", *sklassname = "?";
|
||||
|
||||
funcname = PyObject_GetAttrString(func, "__name__");
|
||||
if (funcname == NULL)
|
||||
PyErr_Clear();
|
||||
else if (!PyString_Check(funcname)) {
|
||||
Py_DECREF(funcname);
|
||||
funcname = NULL;
|
||||
}
|
||||
else {
|
||||
funcname = PyObject_GetAttrString(func,"__name__");
|
||||
if (funcname == NULL)
|
||||
PyErr_Clear();
|
||||
else
|
||||
sfuncname = PyString_AS_STRING(funcname);
|
||||
klassname = PyObject_GetAttrString(klass, "__name__");
|
||||
if (klassname == NULL)
|
||||
PyErr_Clear();
|
||||
else if (!PyString_Check(klassname)) {
|
||||
Py_DECREF(klassname);
|
||||
klassname = NULL;
|
||||
}
|
||||
if (funcname != NULL && PyString_Check(funcname))
|
||||
fname = PyString_AS_STRING(funcname);
|
||||
else
|
||||
fname = "?";
|
||||
if (fclassname != NULL && PyString_Check(fclassname))
|
||||
fcname = PyString_AsString(fclassname);
|
||||
else
|
||||
fcname = "?";
|
||||
sklassname = PyString_AS_STRING(klassname);
|
||||
if (self == NULL)
|
||||
sprintf(buf, "<unbound method %.100s.%.100s>", fcname, fname);
|
||||
sprintf(buffer, "<unbound method %.100s.%.100s>",
|
||||
sklassname, sfuncname);
|
||||
else {
|
||||
iclassname = self->in_class->cl_name;
|
||||
if (iclassname != NULL && PyString_Check(iclassname))
|
||||
icname = PyString_AsString(iclassname);
|
||||
else
|
||||
icname = "?";
|
||||
sprintf(buf, "<method %.60s.%.60s of %.60s instance at %p>",
|
||||
fcname, fname, icname, self);
|
||||
/* XXX Shouldn't use repr() here! */
|
||||
PyObject *selfrepr = PyObject_Repr(self);
|
||||
if (selfrepr == NULL)
|
||||
goto fail;
|
||||
if (!PyString_Check(selfrepr)) {
|
||||
Py_DECREF(selfrepr);
|
||||
goto fail;
|
||||
}
|
||||
sprintf(buffer, "<bound method %.60s.%.60s of %.60s>",
|
||||
sklassname, sfuncname, PyString_AS_STRING(selfrepr));
|
||||
Py_DECREF(selfrepr);
|
||||
}
|
||||
result = PyString_FromString(buffer);
|
||||
fail:
|
||||
Py_XDECREF(funcname);
|
||||
return PyString_FromString(buf);
|
||||
Py_XDECREF(klassname);
|
||||
return result;
|
||||
}
|
||||
|
||||
static long
|
||||
|
@ -2105,6 +2141,57 @@ instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw)
|
||||
{
|
||||
PyObject *self = PyMethod_GET_SELF(func);
|
||||
PyObject *class = PyMethod_GET_CLASS(func);
|
||||
PyObject *result;
|
||||
|
||||
func = PyMethod_GET_FUNCTION(func);
|
||||
if (self == NULL) {
|
||||
/* Unbound methods must be called with an instance of
|
||||
the class (or a derived class) as first argument */
|
||||
int ok;
|
||||
if (PyTuple_Size(arg) >= 1)
|
||||
self = PyTuple_GET_ITEM(arg, 0);
|
||||
if (self == NULL)
|
||||
ok = 0;
|
||||
else {
|
||||
ok = PyObject_IsInstance(self, class);
|
||||
if (ok < 0)
|
||||
return NULL;
|
||||
}
|
||||
if (!ok) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"unbound method %s%s must be "
|
||||
"called with instance as first argument",
|
||||
PyEval_GetFuncName(func),
|
||||
PyEval_GetFuncDesc(func));
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(arg);
|
||||
}
|
||||
else {
|
||||
int argcount = PyTuple_Size(arg);
|
||||
PyObject *newarg = PyTuple_New(argcount + 1);
|
||||
int i;
|
||||
if (newarg == NULL)
|
||||
return NULL;
|
||||
Py_INCREF(self);
|
||||
PyTuple_SET_ITEM(newarg, 0, self);
|
||||
for (i = 0; i < argcount; i++) {
|
||||
PyObject *v = PyTuple_GET_ITEM(arg, i);
|
||||
Py_XINCREF(v);
|
||||
PyTuple_SET_ITEM(newarg, i+1, v);
|
||||
}
|
||||
arg = newarg;
|
||||
}
|
||||
result = PyObject_Call((PyObject *)func, arg, kw);
|
||||
Py_DECREF(arg);
|
||||
return result;
|
||||
}
|
||||
|
||||
PyTypeObject PyMethod_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
|
@ -2121,7 +2208,7 @@ PyTypeObject PyMethod_Type = {
|
|||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)instancemethod_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
instancemethod_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
(getattrofunc)instancemethod_getattro, /* tp_getattro */
|
||||
(setattrofunc)instancemethod_setattro, /* tp_setattro */
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#ifndef WITHOUT_COMPLEX
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
/* Precisions used by repr() and str(), respectively.
|
||||
|
||||
|
@ -182,6 +183,17 @@ c_powi(Py_complex x, long n)
|
|||
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval)
|
||||
{
|
||||
PyObject *op;
|
||||
|
||||
op = PyType_GenericAlloc(type, 0);
|
||||
if (op != NULL)
|
||||
((PyComplexObject *)op)->cval = cval;
|
||||
return op;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyComplex_FromCComplex(Py_complex cval)
|
||||
{
|
||||
|
@ -196,6 +208,15 @@ PyComplex_FromCComplex(Py_complex cval)
|
|||
return (PyObject *) op;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
complex_subtype_from_doubles(PyTypeObject *type, double real, double imag)
|
||||
{
|
||||
Py_complex c;
|
||||
c.real = real;
|
||||
c.imag = imag;
|
||||
return complex_subtype_from_c_complex(type, c);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyComplex_FromDoubles(double real, double imag)
|
||||
{
|
||||
|
@ -559,19 +580,261 @@ static PyMethodDef complex_methods[] = {
|
|||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static struct memberlist complex_members[] = {
|
||||
{"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0},
|
||||
{"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0},
|
||||
{0},
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
complex_getattr(PyComplexObject *self, char *name)
|
||||
complex_subtype_from_string(PyTypeObject *type, PyObject *v)
|
||||
{
|
||||
if (strcmp(name, "real") == 0)
|
||||
return (PyObject *)PyFloat_FromDouble(self->cval.real);
|
||||
else if (strcmp(name, "imag") == 0)
|
||||
return (PyObject *)PyFloat_FromDouble(self->cval.imag);
|
||||
else if (strcmp(name, "__members__") == 0)
|
||||
return Py_BuildValue("[ss]", "imag", "real");
|
||||
return Py_FindMethod(complex_methods, (PyObject *)self, name);
|
||||
extern double strtod(const char *, char **);
|
||||
const char *s, *start;
|
||||
char *end;
|
||||
double x=0.0, y=0.0, z;
|
||||
int got_re=0, got_im=0, done=0;
|
||||
int digit_or_dot;
|
||||
int sw_error=0;
|
||||
int sign;
|
||||
char buffer[256]; /* For errors */
|
||||
char s_buffer[256];
|
||||
int len;
|
||||
|
||||
if (PyString_Check(v)) {
|
||||
s = PyString_AS_STRING(v);
|
||||
len = PyString_GET_SIZE(v);
|
||||
}
|
||||
else if (PyUnicode_Check(v)) {
|
||||
if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"complex() literal too large to convert");
|
||||
return NULL;
|
||||
}
|
||||
if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
|
||||
PyUnicode_GET_SIZE(v),
|
||||
s_buffer,
|
||||
NULL))
|
||||
return NULL;
|
||||
s = s_buffer;
|
||||
len = (int)strlen(s);
|
||||
}
|
||||
else if (PyObject_AsCharBuffer(v, &s, &len)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"complex() arg is not a string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* position on first nonblank */
|
||||
start = s;
|
||||
while (*s && isspace(Py_CHARMASK(*s)))
|
||||
s++;
|
||||
if (s[0] == '\0') {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"complex() arg is an empty string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
z = -1.0;
|
||||
sign = 1;
|
||||
do {
|
||||
|
||||
switch (*s) {
|
||||
|
||||
case '\0':
|
||||
if (s-start != len) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"complex() arg contains a null byte");
|
||||
return NULL;
|
||||
}
|
||||
if(!done) sw_error=1;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
sign = -1;
|
||||
/* Fallthrough */
|
||||
case '+':
|
||||
if (done) sw_error=1;
|
||||
s++;
|
||||
if ( *s=='\0'||*s=='+'||*s=='-' ||
|
||||
isspace(Py_CHARMASK(*s)) ) sw_error=1;
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
case 'j':
|
||||
if (got_im || done) {
|
||||
sw_error = 1;
|
||||
break;
|
||||
}
|
||||
if (z<0.0) {
|
||||
y=sign;
|
||||
}
|
||||
else{
|
||||
y=sign*z;
|
||||
}
|
||||
got_im=1;
|
||||
s++;
|
||||
if (*s!='+' && *s!='-' )
|
||||
done=1;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isspace(Py_CHARMASK(*s))) {
|
||||
while (*s && isspace(Py_CHARMASK(*s)))
|
||||
s++;
|
||||
if (s[0] != '\0')
|
||||
sw_error=1;
|
||||
else
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
digit_or_dot =
|
||||
(*s=='.' || isdigit(Py_CHARMASK(*s)));
|
||||
if (done||!digit_or_dot) {
|
||||
sw_error=1;
|
||||
break;
|
||||
}
|
||||
errno = 0;
|
||||
PyFPE_START_PROTECT("strtod", return 0)
|
||||
z = strtod(s, &end) ;
|
||||
PyFPE_END_PROTECT(z)
|
||||
if (errno != 0) {
|
||||
sprintf(buffer,
|
||||
"float() out of range: %.150s", s);
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
buffer);
|
||||
return NULL;
|
||||
}
|
||||
s=end;
|
||||
if (*s=='J' || *s=='j') {
|
||||
|
||||
break;
|
||||
}
|
||||
if (got_re) {
|
||||
sw_error=1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* accept a real part */
|
||||
x=sign*z;
|
||||
got_re=1;
|
||||
if (got_im) done=1;
|
||||
z = -1.0;
|
||||
sign = 1;
|
||||
break;
|
||||
|
||||
} /* end of switch */
|
||||
|
||||
} while (*s!='\0' && !sw_error);
|
||||
|
||||
if (sw_error) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"complex() arg is a malformed string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return complex_subtype_from_doubles(type, x, y);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *r, *i, *tmp;
|
||||
PyNumberMethods *nbr, *nbi = NULL;
|
||||
Py_complex cr, ci;
|
||||
int own_r = 0;
|
||||
static char *kwlist[] = {"real", "imag", 0};
|
||||
|
||||
r = Py_False;
|
||||
i = NULL;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:complex", kwlist,
|
||||
&r, &i))
|
||||
return NULL;
|
||||
if (PyString_Check(r) || PyUnicode_Check(r))
|
||||
return complex_subtype_from_string(type, r);
|
||||
if ((nbr = r->ob_type->tp_as_number) == NULL ||
|
||||
nbr->nb_float == NULL ||
|
||||
(i != NULL &&
|
||||
((nbi = i->ob_type->tp_as_number) == NULL ||
|
||||
nbi->nb_float == NULL))) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"complex() arg can't be converted to complex");
|
||||
return NULL;
|
||||
}
|
||||
/* XXX Hack to support classes with __complex__ method */
|
||||
if (PyInstance_Check(r)) {
|
||||
static PyObject *complexstr;
|
||||
PyObject *f;
|
||||
if (complexstr == NULL) {
|
||||
complexstr = PyString_InternFromString("__complex__");
|
||||
if (complexstr == NULL)
|
||||
return NULL;
|
||||
}
|
||||
f = PyObject_GetAttr(r, complexstr);
|
||||
if (f == NULL)
|
||||
PyErr_Clear();
|
||||
else {
|
||||
PyObject *args = Py_BuildValue("()");
|
||||
if (args == NULL)
|
||||
return NULL;
|
||||
r = PyEval_CallObject(f, args);
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(f);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
own_r = 1;
|
||||
}
|
||||
}
|
||||
if (PyComplex_Check(r)) {
|
||||
cr = ((PyComplexObject*)r)->cval;
|
||||
if (own_r) {
|
||||
Py_DECREF(r);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmp = PyNumber_Float(r);
|
||||
if (own_r) {
|
||||
Py_DECREF(r);
|
||||
}
|
||||
if (tmp == NULL)
|
||||
return NULL;
|
||||
if (!PyFloat_Check(tmp)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"float(r) didn't return a float");
|
||||
Py_DECREF(tmp);
|
||||
return NULL;
|
||||
}
|
||||
cr.real = PyFloat_AsDouble(tmp);
|
||||
Py_DECREF(tmp);
|
||||
cr.imag = 0.0;
|
||||
}
|
||||
if (i == NULL) {
|
||||
ci.real = 0.0;
|
||||
ci.imag = 0.0;
|
||||
}
|
||||
else if (PyComplex_Check(i))
|
||||
ci = ((PyComplexObject*)i)->cval;
|
||||
else {
|
||||
tmp = (*nbi->nb_float)(i);
|
||||
if (tmp == NULL)
|
||||
return NULL;
|
||||
ci.real = PyFloat_AsDouble(tmp);
|
||||
Py_DECREF(tmp);
|
||||
ci.imag = 0.;
|
||||
}
|
||||
cr.real -= ci.imag;
|
||||
cr.imag += ci.real;
|
||||
return complex_subtype_from_c_complex(type, cr);
|
||||
}
|
||||
|
||||
static char complex_doc[] =
|
||||
"complex(real[, imag]) -> complex number\n\
|
||||
\n\
|
||||
Create a complex number from a real part and an optional imaginary part.\n\
|
||||
This is equivalent to (real + imag*1j) where imag defaults to 0.";
|
||||
|
||||
static PyNumberMethods complex_as_number = {
|
||||
(binaryfunc)complex_add, /* nb_add */
|
||||
(binaryfunc)complex_sub, /* nb_subtract */
|
||||
|
@ -606,7 +869,7 @@ PyTypeObject PyComplex_Type = {
|
|||
0,
|
||||
(destructor)complex_dealloc, /* tp_dealloc */
|
||||
(printfunc)complex_print, /* tp_print */
|
||||
(getattrfunc)complex_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)complex_repr, /* tp_repr */
|
||||
|
@ -616,14 +879,28 @@ PyTypeObject PyComplex_Type = {
|
|||
(hashfunc)complex_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
(reprfunc)complex_str, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
complex_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
complex_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
complex_methods, /* tp_methods */
|
||||
complex_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
complex_new, /* tp_new */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
854
Objects/descrobject.c
Normal file
854
Objects/descrobject.c
Normal file
|
@ -0,0 +1,854 @@
|
|||
/* Descriptors -- a new, flexible way to describe attributes */
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h" /* Why is this not included in Python.h? */
|
||||
|
||||
/* Various kinds of descriptor objects */
|
||||
|
||||
#define COMMON \
|
||||
PyObject_HEAD \
|
||||
PyTypeObject *d_type; \
|
||||
PyObject *d_name
|
||||
|
||||
typedef struct {
|
||||
COMMON;
|
||||
} PyDescrObject;
|
||||
|
||||
typedef struct {
|
||||
COMMON;
|
||||
PyMethodDef *d_method;
|
||||
} PyMethodDescrObject;
|
||||
|
||||
typedef struct {
|
||||
COMMON;
|
||||
struct memberlist *d_member;
|
||||
} PyMemberDescrObject;
|
||||
|
||||
typedef struct {
|
||||
COMMON;
|
||||
struct getsetlist *d_getset;
|
||||
} PyGetSetDescrObject;
|
||||
|
||||
typedef struct {
|
||||
COMMON;
|
||||
struct wrapperbase *d_base;
|
||||
void *d_wrapped; /* This can be any function pointer */
|
||||
} PyWrapperDescrObject;
|
||||
|
||||
static void
|
||||
descr_dealloc(PyDescrObject *descr)
|
||||
{
|
||||
Py_XDECREF(descr->d_type);
|
||||
Py_XDECREF(descr->d_name);
|
||||
PyObject_DEL(descr);
|
||||
}
|
||||
|
||||
static char *
|
||||
descr_name(PyDescrObject *descr)
|
||||
{
|
||||
if (descr->d_name != NULL && PyString_Check(descr->d_name))
|
||||
return PyString_AS_STRING(descr->d_name);
|
||||
else
|
||||
return "?";
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
descr_repr(PyDescrObject *descr, char *format)
|
||||
{
|
||||
char buffer[500];
|
||||
|
||||
sprintf(buffer, format, descr_name(descr), descr->d_type->tp_name);
|
||||
return PyString_FromString(buffer);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_repr(PyMethodDescrObject *descr)
|
||||
{
|
||||
return descr_repr((PyDescrObject *)descr,
|
||||
"<method '%.300s' of '%.100s' objects>");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
member_repr(PyMemberDescrObject *descr)
|
||||
{
|
||||
return descr_repr((PyDescrObject *)descr,
|
||||
"<member '%.300s' of '%.100s' objects>");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
getset_repr(PyGetSetDescrObject *descr)
|
||||
{
|
||||
return descr_repr((PyDescrObject *)descr,
|
||||
"<attribute '%.300s' of '%.100s' objects>");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
wrapper_repr(PyWrapperDescrObject *descr)
|
||||
{
|
||||
return descr_repr((PyDescrObject *)descr,
|
||||
"<slot wrapper '%.300s' of '%.100s' objects>");
|
||||
}
|
||||
|
||||
static int
|
||||
descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
|
||||
PyObject **pres)
|
||||
{
|
||||
if (obj == NULL || obj == Py_None) {
|
||||
Py_INCREF(descr);
|
||||
*pres = (PyObject *)descr;
|
||||
return 1;
|
||||
}
|
||||
if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%.200s' for '%.100s' objects "
|
||||
"doesn't apply to '%.100s' object",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name,
|
||||
obj->ob_type->tp_name);
|
||||
*pres = NULL;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||
return res;
|
||||
return PyCFunction_New(descr->d_method, obj);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||
return res;
|
||||
return PyMember_Get((char *)obj, descr->d_member,
|
||||
descr->d_member->name);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||
return res;
|
||||
if (descr->d_getset->get != NULL)
|
||||
return descr->d_getset->get(obj, descr->d_getset->closure);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"attribute '%300s' of '%.100s' objects is not readable",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||
return res;
|
||||
return PyWrapper_New((PyObject *)descr, obj);
|
||||
}
|
||||
|
||||
static int
|
||||
descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
|
||||
int *pres)
|
||||
{
|
||||
assert(obj != NULL);
|
||||
if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%.200s' for '%.100s' objects "
|
||||
"doesn't apply to '%.100s' object",
|
||||
descr_name(descr),
|
||||
descr->d_type->tp_name,
|
||||
obj->ob_type->tp_name);
|
||||
*pres = -1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
|
||||
return res;
|
||||
return PyMember_Set((char *)obj, descr->d_member,
|
||||
descr->d_member->name, value);
|
||||
}
|
||||
|
||||
static int
|
||||
getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
|
||||
return res;
|
||||
if (descr->d_getset->set != NULL)
|
||||
return descr->d_getset->set(obj, value,
|
||||
descr->d_getset->closure);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"attribute '%300s' of '%.100s' objects is not writable",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
int argc;
|
||||
PyObject *self, *func, *result;
|
||||
|
||||
/* Make sure that the first argument is acceptable as 'self' */
|
||||
assert(PyTuple_Check(args));
|
||||
argc = PyTuple_GET_SIZE(args);
|
||||
if (argc < 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%.300s' of '%.100s' "
|
||||
"object needs an argument",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
self = PyTuple_GET_ITEM(args, 0);
|
||||
if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%.200s' "
|
||||
"requires a '%.100s' object "
|
||||
"but received a '%.100s'",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name,
|
||||
self->ob_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
func = PyCFunction_New(descr->d_method, self);
|
||||
if (func == NULL)
|
||||
return NULL;
|
||||
args = PyTuple_GetSlice(args, 1, argc);
|
||||
if (args == NULL) {
|
||||
Py_DECREF(func);
|
||||
return NULL;
|
||||
}
|
||||
result = PyEval_CallObjectWithKeywords(func, args, kwds);
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(func);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
int argc;
|
||||
PyObject *self, *func, *result;
|
||||
|
||||
/* Make sure that the first argument is acceptable as 'self' */
|
||||
assert(PyTuple_Check(args));
|
||||
argc = PyTuple_GET_SIZE(args);
|
||||
if (argc < 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%.300s' of '%.100s' "
|
||||
"object needs an argument",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
self = PyTuple_GET_ITEM(args, 0);
|
||||
if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%.200s' "
|
||||
"requires a '%.100s' object "
|
||||
"but received a '%.100s'",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name,
|
||||
self->ob_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
func = PyWrapper_New((PyObject *)descr, self);
|
||||
if (func == NULL)
|
||||
return NULL;
|
||||
args = PyTuple_GetSlice(args, 1, argc);
|
||||
if (args == NULL) {
|
||||
Py_DECREF(func);
|
||||
return NULL;
|
||||
}
|
||||
result = PyEval_CallObjectWithKeywords(func, args, kwds);
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(func);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
member_get_doc(PyMethodDescrObject *descr, void *closure)
|
||||
{
|
||||
if (descr->d_method->ml_doc == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
return PyString_FromString(descr->d_method->ml_doc);
|
||||
}
|
||||
|
||||
static struct memberlist descr_members[] = {
|
||||
{"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
|
||||
{"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
|
||||
{0}
|
||||
};
|
||||
|
||||
static struct getsetlist member_getset[] = {
|
||||
{"__doc__", (getter)member_get_doc},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
|
||||
{
|
||||
if (descr->d_base->doc == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
return PyString_FromString(descr->d_base->doc);
|
||||
}
|
||||
|
||||
static struct getsetlist wrapper_getset[] = {
|
||||
{"__doc__", (getter)wrapper_get_doc},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyTypeObject PyMethodDescr_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"method_descriptor",
|
||||
sizeof(PyMethodDescrObject),
|
||||
0,
|
||||
(destructor)descr_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)method_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
(ternaryfunc)methoddescr_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
descr_members, /* tp_members */
|
||||
member_getset, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
(descrgetfunc)method_get, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
};
|
||||
|
||||
static PyTypeObject PyMemberDescr_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"member_descriptor",
|
||||
sizeof(PyMemberDescrObject),
|
||||
0,
|
||||
(destructor)descr_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)member_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
(ternaryfunc)0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
descr_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
(descrgetfunc)member_get, /* tp_descr_get */
|
||||
(descrsetfunc)member_set, /* tp_descr_set */
|
||||
};
|
||||
|
||||
static PyTypeObject PyGetSetDescr_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"getset_descriptor",
|
||||
sizeof(PyGetSetDescrObject),
|
||||
0,
|
||||
(destructor)descr_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)getset_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
(ternaryfunc)0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
descr_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
(descrgetfunc)getset_get, /* tp_descr_get */
|
||||
(descrsetfunc)getset_set, /* tp_descr_set */
|
||||
};
|
||||
|
||||
static PyTypeObject PyWrapperDescr_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"wrapper_descriptor",
|
||||
sizeof(PyWrapperDescrObject),
|
||||
0,
|
||||
(destructor)descr_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)wrapper_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
(ternaryfunc)wrapperdescr_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
descr_members, /* tp_members */
|
||||
wrapper_getset, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
(descrgetfunc)wrapper_get, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
};
|
||||
|
||||
static PyDescrObject *
|
||||
descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
|
||||
{
|
||||
PyDescrObject *descr;
|
||||
|
||||
descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
|
||||
if (descr != NULL) {
|
||||
Py_XINCREF(type);
|
||||
descr->d_type = type;
|
||||
descr->d_name = PyString_InternFromString(name);
|
||||
if (descr->d_name == NULL) {
|
||||
Py_DECREF(descr);
|
||||
descr = NULL;
|
||||
}
|
||||
}
|
||||
return descr;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
|
||||
{
|
||||
PyMethodDescrObject *descr;
|
||||
|
||||
descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
|
||||
type, method->ml_name);
|
||||
if (descr != NULL)
|
||||
descr->d_method = method;
|
||||
return (PyObject *)descr;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyDescr_NewMember(PyTypeObject *type, struct memberlist *member)
|
||||
{
|
||||
PyMemberDescrObject *descr;
|
||||
|
||||
descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
|
||||
type, member->name);
|
||||
if (descr != NULL)
|
||||
descr->d_member = member;
|
||||
return (PyObject *)descr;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyDescr_NewGetSet(PyTypeObject *type, struct getsetlist *getset)
|
||||
{
|
||||
PyGetSetDescrObject *descr;
|
||||
|
||||
descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
|
||||
type, getset->name);
|
||||
if (descr != NULL)
|
||||
descr->d_getset = getset;
|
||||
return (PyObject *)descr;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
|
||||
{
|
||||
PyWrapperDescrObject *descr;
|
||||
|
||||
descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
|
||||
type, base->name);
|
||||
if (descr != NULL) {
|
||||
descr->d_base = base;
|
||||
descr->d_wrapped = wrapped;
|
||||
}
|
||||
return (PyObject *)descr;
|
||||
}
|
||||
|
||||
int
|
||||
PyDescr_IsData(PyObject *d)
|
||||
{
|
||||
return d->ob_type->tp_descr_set != NULL;
|
||||
}
|
||||
|
||||
|
||||
/* --- Readonly proxy for dictionaries (actually any mapping) --- */
|
||||
|
||||
/* This has no reason to be in this file except that adding new files is a
|
||||
bit of a pain */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *dict;
|
||||
} proxyobject;
|
||||
|
||||
static int
|
||||
proxy_len(proxyobject *pp)
|
||||
{
|
||||
return PyObject_Size(pp->dict);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_getitem(proxyobject *pp, PyObject *key)
|
||||
{
|
||||
return PyObject_GetItem(pp->dict, key);
|
||||
}
|
||||
|
||||
static PyMappingMethods proxy_as_mapping = {
|
||||
(inquiry)proxy_len, /* mp_length */
|
||||
(binaryfunc)proxy_getitem, /* mp_subscript */
|
||||
0, /* mp_ass_subscript */
|
||||
};
|
||||
|
||||
static int
|
||||
proxy_contains(proxyobject *pp, PyObject *key)
|
||||
{
|
||||
return PySequence_Contains(pp->dict, key);
|
||||
}
|
||||
|
||||
static PySequenceMethods proxy_as_sequence = {
|
||||
0, /* sq_length */
|
||||
0, /* sq_concat */
|
||||
0, /* sq_repeat */
|
||||
0, /* sq_item */
|
||||
0, /* sq_slice */
|
||||
0, /* sq_ass_item */
|
||||
0, /* sq_ass_slice */
|
||||
(objobjproc)proxy_contains, /* sq_contains */
|
||||
0, /* sq_inplace_concat */
|
||||
0, /* sq_inplace_repeat */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
proxy_has_key(proxyobject *pp, PyObject *args)
|
||||
{
|
||||
PyObject *key;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:has_key", &key))
|
||||
return NULL;
|
||||
return PyInt_FromLong(PySequence_Contains(pp->dict, key));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_get(proxyobject *pp, PyObject *args)
|
||||
{
|
||||
PyObject *key, *def = Py_None;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
|
||||
return NULL;
|
||||
return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_keys(proxyobject *pp, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":keys"))
|
||||
return NULL;
|
||||
return PyMapping_Keys(pp->dict);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_values(proxyobject *pp, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":values"))
|
||||
return NULL;
|
||||
return PyMapping_Values(pp->dict);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_items(proxyobject *pp, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":items"))
|
||||
return NULL;
|
||||
return PyMapping_Items(pp->dict);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_copy(proxyobject *pp, PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ":copy"))
|
||||
return NULL;
|
||||
return PyObject_CallMethod(pp->dict, "copy", NULL);
|
||||
}
|
||||
|
||||
static PyMethodDef proxy_methods[] = {
|
||||
{"has_key", (PyCFunction)proxy_has_key, METH_VARARGS, "XXX"},
|
||||
{"get", (PyCFunction)proxy_get, METH_VARARGS, "XXX"},
|
||||
{"keys", (PyCFunction)proxy_keys, METH_VARARGS, "XXX"},
|
||||
{"values", (PyCFunction)proxy_values, METH_VARARGS, "XXX"},
|
||||
{"items", (PyCFunction)proxy_items, METH_VARARGS, "XXX"},
|
||||
{"copy", (PyCFunction)proxy_copy, METH_VARARGS, "XXX"},
|
||||
{0}
|
||||
};
|
||||
|
||||
static void
|
||||
proxy_dealloc(proxyobject *pp)
|
||||
{
|
||||
Py_DECREF(pp->dict);
|
||||
PyObject_DEL(pp);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_getiter(proxyobject *pp)
|
||||
{
|
||||
return PyObject_GetIter(pp->dict);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
proxy_str(proxyobject *pp)
|
||||
{
|
||||
return PyObject_Str(pp->dict);
|
||||
}
|
||||
|
||||
PyTypeObject proxytype = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /* ob_size */
|
||||
"dict-proxy", /* tp_name */
|
||||
sizeof(proxyobject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)proxy_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
&proxy_as_sequence, /* tp_as_sequence */
|
||||
&proxy_as_mapping, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
(reprfunc)proxy_str, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)proxy_getiter, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
proxy_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyDictProxy_New(PyObject *dict)
|
||||
{
|
||||
proxyobject *pp;
|
||||
|
||||
pp = PyObject_NEW(proxyobject, &proxytype);
|
||||
if (pp != NULL) {
|
||||
Py_INCREF(dict);
|
||||
pp->dict = dict;
|
||||
}
|
||||
return (PyObject *)pp;
|
||||
}
|
||||
|
||||
|
||||
/* --- Wrapper object for "slot" methods --- */
|
||||
|
||||
/* This has no reason to be in this file except that adding new files is a
|
||||
bit of a pain */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyWrapperDescrObject *descr;
|
||||
PyObject *self;
|
||||
} wrapperobject;
|
||||
|
||||
static void
|
||||
wrapper_dealloc(wrapperobject *wp)
|
||||
{
|
||||
Py_XDECREF(wp->descr);
|
||||
Py_XDECREF(wp->self);
|
||||
PyObject_DEL(wp);
|
||||
}
|
||||
|
||||
static PyMethodDef wrapper_methods[] = {
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
wrapper_name(wrapperobject *wp)
|
||||
{
|
||||
char *s = wp->descr->d_base->name;
|
||||
|
||||
return PyString_FromString(s);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
wrapper_doc(wrapperobject *wp)
|
||||
{
|
||||
char *s = wp->descr->d_base->doc;
|
||||
|
||||
if (s == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
else {
|
||||
return PyString_FromString(s);
|
||||
}
|
||||
}
|
||||
|
||||
static struct getsetlist wrapper_getsets[] = {
|
||||
{"__name__", (getter)wrapper_name},
|
||||
{"__doc__", (getter)wrapper_doc},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
wrapperfunc wrapper = wp->descr->d_base->wrapper;
|
||||
PyObject *self = wp->self;
|
||||
|
||||
return (*wrapper)(self, args, wp->descr->d_wrapped);
|
||||
}
|
||||
|
||||
PyTypeObject wrappertype = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /* ob_size */
|
||||
"method-wrapper", /* tp_name */
|
||||
sizeof(wrapperobject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)wrapper_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
(ternaryfunc)wrapper_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
wrapper_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
wrapper_getsets, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyWrapper_New(PyObject *d, PyObject *self)
|
||||
{
|
||||
wrapperobject *wp;
|
||||
PyWrapperDescrObject *descr;
|
||||
|
||||
assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
|
||||
descr = (PyWrapperDescrObject *)d;
|
||||
assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
|
||||
|
||||
wp = PyObject_NEW(wrapperobject, &wrappertype);
|
||||
if (wp != NULL) {
|
||||
Py_INCREF(descr);
|
||||
wp->descr = descr;
|
||||
Py_INCREF(self);
|
||||
wp->self = self;
|
||||
}
|
||||
return (PyObject *)wp;
|
||||
}
|
|
@ -3,15 +3,8 @@
|
|||
|
||||
#include "Python.h"
|
||||
|
||||
/* MINSIZE is the minimum size of a dictionary. This many slots are
|
||||
* allocated directly in the dict object (in the ma_smalltable member).
|
||||
* It must be a power of 2, and at least 4. 8 allows dicts with no more than
|
||||
* 5 active entries to live in ma_smalltable (and so avoid an additional
|
||||
* malloc); instrumentation suggested this suffices for the majority of
|
||||
* dicts (consisting mostly of usually-small instance dicts and usually-small
|
||||
* dicts created to pass keyword arguments).
|
||||
*/
|
||||
#define MINSIZE 8
|
||||
typedef PyDictEntry dictentry;
|
||||
typedef PyDictObject dictobject;
|
||||
|
||||
/* Define this out if you don't want conversion statistics on exit. */
|
||||
#undef SHOW_CONVERSION_COUNTS
|
||||
|
@ -116,69 +109,6 @@ equally good collision statistics, needed less code & used less memory.
|
|||
/* Object used as dummy key to fill deleted entries */
|
||||
static PyObject *dummy; /* Initialized by first call to newdictobject() */
|
||||
|
||||
/*
|
||||
There are three kinds of slots in the table:
|
||||
|
||||
1. Unused. me_key == me_value == NULL
|
||||
Does not hold an active (key, value) pair now and never did. Unused can
|
||||
transition to Active upon key insertion. This is the only case in which
|
||||
me_key is NULL, and is each slot's initial state.
|
||||
|
||||
2. Active. me_key != NULL and me_key != dummy and me_value != NULL
|
||||
Holds an active (key, value) pair. Active can transition to Dummy upon
|
||||
key deletion. This is the only case in which me_value != NULL.
|
||||
|
||||
3. Dummy. me_key == dummy and me_value == NULL
|
||||
Previously held an active (key, value) pair, but that was deleted and an
|
||||
active pair has not yet overwritten the slot. Dummy can transition to
|
||||
Active upon key insertion. Dummy slots cannot be made Unused again
|
||||
(cannot have me_key set to NULL), else the probe sequence in case of
|
||||
collision would have no way to know they were once active.
|
||||
|
||||
Note: .popitem() abuses the me_hash field of an Unused or Dummy slot to
|
||||
hold a search finger. The me_hash field of Unused or Dummy slots has no
|
||||
meaning otherwise.
|
||||
*/
|
||||
typedef struct {
|
||||
long me_hash; /* cached hash code of me_key */
|
||||
PyObject *me_key;
|
||||
PyObject *me_value;
|
||||
#ifdef USE_CACHE_ALIGNED
|
||||
long aligner;
|
||||
#endif
|
||||
} dictentry;
|
||||
|
||||
/*
|
||||
To ensure the lookup algorithm terminates, there must be at least one Unused
|
||||
slot (NULL key) in the table.
|
||||
The value ma_fill is the number of non-NULL keys (sum of Active and Dummy);
|
||||
ma_used is the number of non-NULL, non-dummy keys (== the number of non-NULL
|
||||
values == the number of Active items).
|
||||
To avoid slowing down lookups on a near-full table, we resize the table when
|
||||
it's two-thirds full.
|
||||
*/
|
||||
typedef struct dictobject dictobject;
|
||||
struct dictobject {
|
||||
PyObject_HEAD
|
||||
int ma_fill; /* # Active + # Dummy */
|
||||
int ma_used; /* # Active */
|
||||
|
||||
/* The table contains ma_mask + 1 slots, and that's a power of 2.
|
||||
* We store the mask instead of the size because the mask is more
|
||||
* frequently needed.
|
||||
*/
|
||||
int ma_mask;
|
||||
|
||||
/* ma_table points to ma_smalltable for small tables, else to
|
||||
* additional malloc'ed memory. ma_table is never NULL! This rule
|
||||
* saves repeated runtime null-tests in the workhorse getitem and
|
||||
* setitem calls.
|
||||
*/
|
||||
dictentry *ma_table;
|
||||
dictentry *(*ma_lookup)(dictobject *mp, PyObject *key, long hash);
|
||||
dictentry ma_smalltable[MINSIZE];
|
||||
};
|
||||
|
||||
/* forward declarations */
|
||||
static dictentry *
|
||||
lookdict_string(dictobject *mp, PyObject *key, long hash);
|
||||
|
@ -196,12 +126,24 @@ show_counts(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Set dictobject* mp to empty but w/ MINSIZE slots, using ma_smalltable. */
|
||||
#define empty_to_minsize(mp) do { \
|
||||
memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \
|
||||
/* Initialization macros.
|
||||
There are two ways to create a dict: PyDict_New() is the main C API
|
||||
function, and the tp_new slot maps to dict_new(). In the latter case we
|
||||
can save a little time over what PyDict_New does because it's guaranteed
|
||||
that the PyDictObject struct is already zeroed out.
|
||||
Everyone except dict_new() should use EMPTY_TO_MINSIZE (unless they have
|
||||
an excellent reason not to).
|
||||
*/
|
||||
|
||||
#define INIT_NONZERO_DICT_SLOTS(mp) do { \
|
||||
(mp)->ma_table = (mp)->ma_smalltable; \
|
||||
(mp)->ma_mask = MINSIZE - 1; \
|
||||
(mp)->ma_mask = PyDict_MINSIZE - 1; \
|
||||
} while(0)
|
||||
|
||||
#define EMPTY_TO_MINSIZE(mp) do { \
|
||||
memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \
|
||||
(mp)->ma_used = (mp)->ma_fill = 0; \
|
||||
INIT_NONZERO_DICT_SLOTS(mp); \
|
||||
} while(0)
|
||||
|
||||
PyObject *
|
||||
|
@ -219,7 +161,7 @@ PyDict_New(void)
|
|||
mp = PyObject_NEW(dictobject, &PyDict_Type);
|
||||
if (mp == NULL)
|
||||
return NULL;
|
||||
empty_to_minsize(mp);
|
||||
EMPTY_TO_MINSIZE(mp);
|
||||
mp->ma_lookup = lookdict_string;
|
||||
#ifdef SHOW_CONVERSION_COUNTS
|
||||
++created;
|
||||
|
@ -418,7 +360,10 @@ insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value)
|
|||
{
|
||||
PyObject *old_value;
|
||||
register dictentry *ep;
|
||||
ep = (mp->ma_lookup)(mp, key, hash);
|
||||
typedef PyDictEntry *(*lookupfunc)(PyDictObject *, PyObject *, long);
|
||||
|
||||
assert(mp->ma_lookup != NULL);
|
||||
ep = mp->ma_lookup(mp, key, hash);
|
||||
if (ep->me_value != NULL) {
|
||||
old_value = ep->me_value;
|
||||
ep->me_value = value;
|
||||
|
@ -449,12 +394,12 @@ dictresize(dictobject *mp, int minused)
|
|||
dictentry *oldtable, *newtable, *ep;
|
||||
int i;
|
||||
int is_oldtable_malloced;
|
||||
dictentry small_copy[MINSIZE];
|
||||
dictentry small_copy[PyDict_MINSIZE];
|
||||
|
||||
assert(minused >= 0);
|
||||
|
||||
/* Find the smallest table size > minused. */
|
||||
for (newsize = MINSIZE;
|
||||
for (newsize = PyDict_MINSIZE;
|
||||
newsize <= minused && newsize > 0;
|
||||
newsize <<= 1)
|
||||
;
|
||||
|
@ -468,7 +413,7 @@ dictresize(dictobject *mp, int minused)
|
|||
assert(oldtable != NULL);
|
||||
is_oldtable_malloced = oldtable != mp->ma_smalltable;
|
||||
|
||||
if (newsize == MINSIZE) {
|
||||
if (newsize == PyDict_MINSIZE) {
|
||||
/* A large table is shrinking, or we can't get any smaller. */
|
||||
newtable = mp->ma_smalltable;
|
||||
if (newtable == oldtable) {
|
||||
|
@ -649,7 +594,7 @@ PyDict_Clear(PyObject *op)
|
|||
dictentry *ep, *table;
|
||||
int table_is_malloced;
|
||||
int fill;
|
||||
dictentry small_copy[MINSIZE];
|
||||
dictentry small_copy[PyDict_MINSIZE];
|
||||
#ifdef Py_DEBUG
|
||||
int i, n;
|
||||
#endif
|
||||
|
@ -674,7 +619,7 @@ PyDict_Clear(PyObject *op)
|
|||
*/
|
||||
fill = mp->ma_fill;
|
||||
if (table_is_malloced)
|
||||
empty_to_minsize(mp);
|
||||
EMPTY_TO_MINSIZE(mp);
|
||||
|
||||
else if (fill > 0) {
|
||||
/* It's a small table with something that needs to be cleared.
|
||||
|
@ -683,7 +628,7 @@ PyDict_Clear(PyObject *op)
|
|||
*/
|
||||
memcpy(small_copy, table, sizeof(small_copy));
|
||||
table = small_copy;
|
||||
empty_to_minsize(mp);
|
||||
EMPTY_TO_MINSIZE(mp);
|
||||
}
|
||||
/* else it's a small table that's already empty */
|
||||
|
||||
|
@ -1042,32 +987,47 @@ dict_items(register dictobject *mp, PyObject *args)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
dict_update(register dictobject *mp, PyObject *args)
|
||||
dict_update(PyObject *mp, PyObject *args)
|
||||
{
|
||||
PyObject *other;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:update", &other))
|
||||
return NULL;
|
||||
if (PyDict_Update(mp, other) < 0)
|
||||
return NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
int
|
||||
PyDict_Update(PyObject *a, PyObject *b)
|
||||
{
|
||||
register PyDictObject *mp, *other;
|
||||
register int i;
|
||||
dictobject *other;
|
||||
dictentry *entry;
|
||||
PyObject *param;
|
||||
|
||||
/* We accept for the argument either a concrete dictionary object,
|
||||
* or an abstract "mapping" object. For the former, we can do
|
||||
* things quite efficiently. For the latter, we only require that
|
||||
* PyMapping_Keys() and PyObject_GetItem() be supported.
|
||||
*/
|
||||
if (!PyArg_ParseTuple(args, "O:update", ¶m))
|
||||
return NULL;
|
||||
|
||||
if (PyDict_Check(param)) {
|
||||
other = (dictobject*)param;
|
||||
if (a == NULL || !PyDict_Check(a) || b == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
mp = (dictobject*)a;
|
||||
if (PyDict_Check(b)) {
|
||||
other = (dictobject*)b;
|
||||
if (other == mp || other->ma_used == 0)
|
||||
/* a.update(a) or a.update({}); nothing to do */
|
||||
goto done;
|
||||
return 0;
|
||||
/* Do one big resize at the start, rather than
|
||||
* incrementally resizing as we insert new items. Expect
|
||||
* that there will be no (or few) overlapping keys.
|
||||
*/
|
||||
if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) {
|
||||
if (dictresize(mp, (mp->ma_used + other->ma_used)*3/2) != 0)
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i <= other->ma_mask; i++) {
|
||||
entry = &other->ma_table[i];
|
||||
|
@ -1081,7 +1041,7 @@ dict_update(register dictobject *mp, PyObject *args)
|
|||
}
|
||||
else {
|
||||
/* Do it the generic, slower way */
|
||||
PyObject *keys = PyMapping_Keys(param);
|
||||
PyObject *keys = PyMapping_Keys(b);
|
||||
PyObject *iter;
|
||||
PyObject *key, *value;
|
||||
int status;
|
||||
|
@ -1092,37 +1052,34 @@ dict_update(register dictobject *mp, PyObject *args)
|
|||
* AttributeError to percolate up. Might as well
|
||||
* do the same for any other error.
|
||||
*/
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
iter = PyObject_GetIter(keys);
|
||||
Py_DECREF(keys);
|
||||
if (iter == NULL)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
|
||||
value = PyObject_GetItem(param, key);
|
||||
value = PyObject_GetItem(b, key);
|
||||
if (value == NULL) {
|
||||
Py_DECREF(iter);
|
||||
Py_DECREF(key);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
status = PyDict_SetItem((PyObject*)mp, key, value);
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(value);
|
||||
if (status < 0) {
|
||||
Py_DECREF(iter);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
Py_DECREF(iter);
|
||||
if (PyErr_Occurred())
|
||||
/* Iterator completed, via error */
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
done:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -1694,12 +1651,6 @@ static PyMethodDef mapp_methods[] = {
|
|||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
dict_getattr(dictobject *mp, char *name)
|
||||
{
|
||||
return Py_FindMethod(mapp_methods, (PyObject *)mp, name);
|
||||
}
|
||||
|
||||
static int
|
||||
dict_contains(dictobject *mp, PyObject *key)
|
||||
{
|
||||
|
@ -1731,6 +1682,26 @@ static PySequenceMethods dict_as_sequence = {
|
|||
0, /* sq_inplace_repeat */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *self;
|
||||
|
||||
assert(type != NULL && type->tp_alloc != NULL);
|
||||
self = type->tp_alloc(type, 0);
|
||||
if (self != NULL) {
|
||||
PyDictObject *d = (PyDictObject *)self;
|
||||
/* It's guaranteed that tp->alloc zeroed out the struct. */
|
||||
assert(d->ma_table == NULL && d->ma_fill == 0 && d->ma_used == 0);
|
||||
INIT_NONZERO_DICT_SLOTS(d);
|
||||
d->ma_lookup = lookdict_string;
|
||||
#ifdef SHOW_CONVERSION_COUNTS
|
||||
++created;
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dict_iter(dictobject *dict)
|
||||
{
|
||||
|
@ -1745,7 +1716,7 @@ PyTypeObject PyDict_Type = {
|
|||
0,
|
||||
(destructor)dict_dealloc, /* tp_dealloc */
|
||||
(printfunc)dict_print, /* tp_print */
|
||||
(getattrfunc)dict_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
(cmpfunc)dict_compare, /* tp_compare */
|
||||
(reprfunc)dict_repr, /* tp_repr */
|
||||
|
@ -1755,17 +1726,29 @@ PyTypeObject PyDict_Type = {
|
|||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
|
||||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"dictionary type", /* tp_doc */
|
||||
(traverseproc)dict_traverse, /* tp_traverse */
|
||||
(inquiry)dict_tp_clear, /* tp_clear */
|
||||
dict_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)dict_iter, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
mapp_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
dict_new, /* tp_new */
|
||||
};
|
||||
|
||||
/* For backward compatibility with old dictionary interface */
|
||||
|
@ -1873,12 +1856,6 @@ static PyMethodDef dictiter_methods[] = {
|
|||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
dictiter_getattr(dictiterobject *di, char *name)
|
||||
{
|
||||
return Py_FindMethod(dictiter_methods, (PyObject *)di, name);
|
||||
}
|
||||
|
||||
static PyObject *dictiter_iternext(dictiterobject *di)
|
||||
{
|
||||
PyObject *key, *value;
|
||||
|
@ -1903,7 +1880,7 @@ PyTypeObject PyDictIter_Type = {
|
|||
/* methods */
|
||||
(destructor)dictiter_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
(getattrfunc)dictiter_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
|
@ -1913,7 +1890,7 @@ PyTypeObject PyDictIter_Type = {
|
|||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
|
@ -1924,4 +1901,11 @@ PyTypeObject PyDictIter_Type = {
|
|||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)dictiter_getiter, /* tp_iter */
|
||||
(iternextfunc)dictiter_iternext, /* tp_iternext */
|
||||
dictiter_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
};
|
||||
|
|
|
@ -1273,29 +1273,15 @@ static struct memberlist file_memberlist[] = {
|
|||
};
|
||||
|
||||
static PyObject *
|
||||
file_getattr(PyFileObject *f, char *name)
|
||||
get_closed(PyFileObject *f, void *closure)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
res = Py_FindMethod(file_methods, (PyObject *)f, name);
|
||||
if (res != NULL)
|
||||
return res;
|
||||
PyErr_Clear();
|
||||
if (strcmp(name, "closed") == 0)
|
||||
return PyInt_FromLong((long)(f->f_fp == 0));
|
||||
return PyMember_Get((char *)f, file_memberlist, name);
|
||||
return PyInt_FromLong((long)(f->f_fp == 0));
|
||||
}
|
||||
|
||||
static int
|
||||
file_setattr(PyFileObject *f, char *name, PyObject *v)
|
||||
{
|
||||
if (v == NULL) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"can't delete file attributes");
|
||||
return -1;
|
||||
}
|
||||
return PyMember_Set((char *)f, file_memberlist, name, v);
|
||||
}
|
||||
static struct getsetlist file_getsetlist[] = {
|
||||
{"closed", (getter)get_closed, NULL, NULL},
|
||||
{0},
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
file_getiter(PyObject *f)
|
||||
|
@ -1311,27 +1297,32 @@ PyTypeObject PyFile_Type = {
|
|||
0,
|
||||
(destructor)file_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
(getattrfunc)file_getattr, /* tp_getattr */
|
||||
(setattrfunc)file_setattr, /* tp_setattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)file_repr, /* tp_repr */
|
||||
(reprfunc)file_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
file_getiter, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
file_methods, /* tp_methods */
|
||||
file_memberlist, /* tp_members */
|
||||
file_getsetlist, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
};
|
||||
|
||||
/* Interface for the 'soft space' between print items. */
|
||||
|
|
|
@ -636,6 +636,26 @@ float_float(PyObject *v)
|
|||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
float_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *x = Py_False; /* Integer zero */
|
||||
static char *kwlist[] = {"x", 0};
|
||||
|
||||
assert(type == &PyFloat_Type);
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:float", kwlist, &x))
|
||||
return NULL;
|
||||
if (PyString_Check(x))
|
||||
return PyFloat_FromString(x, NULL);
|
||||
return PyNumber_Float(x);
|
||||
}
|
||||
|
||||
static char float_doc[] =
|
||||
"float(x) -> floating point number\n\
|
||||
\n\
|
||||
Convert a string or number to a floating point number, if possible.";
|
||||
|
||||
|
||||
static PyNumberMethods float_as_number = {
|
||||
(binaryfunc)float_add, /*nb_add*/
|
||||
(binaryfunc)float_sub, /*nb_subtract*/
|
||||
|
@ -679,22 +699,40 @@ PyTypeObject PyFloat_Type = {
|
|||
"float",
|
||||
sizeof(PyFloatObject),
|
||||
0,
|
||||
(destructor)float_dealloc, /*tp_dealloc*/
|
||||
(printfunc)float_print, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
(cmpfunc)float_compare, /*tp_compare*/
|
||||
(reprfunc)float_repr, /*tp_repr*/
|
||||
&float_as_number, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
(hashfunc)float_hash, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
(reprfunc)float_str, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
|
||||
(destructor)float_dealloc, /* tp_dealloc */
|
||||
(printfunc)float_print, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
(cmpfunc)float_compare, /* tp_compare */
|
||||
(reprfunc)float_repr, /* tp_repr */
|
||||
&float_as_number, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)float_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
(reprfunc)float_str, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
|
||||
float_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
float_new, /* tp_new */
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -15,7 +15,6 @@ static struct memberlist frame_memberlist[] = {
|
|||
{"f_code", T_OBJECT, OFF(f_code), RO},
|
||||
{"f_builtins", T_OBJECT, OFF(f_builtins),RO},
|
||||
{"f_globals", T_OBJECT, OFF(f_globals), RO},
|
||||
{"f_locals", T_OBJECT, OFF(f_locals), RO},
|
||||
{"f_lasti", T_INT, OFF(f_lasti), RO},
|
||||
{"f_lineno", T_INT, OFF(f_lineno), RO},
|
||||
{"f_restricted",T_INT, OFF(f_restricted),RO},
|
||||
|
@ -27,18 +26,17 @@ static struct memberlist frame_memberlist[] = {
|
|||
};
|
||||
|
||||
static PyObject *
|
||||
frame_getattr(PyFrameObject *f, char *name)
|
||||
frame_getlocals(PyFrameObject *f, void *closure)
|
||||
{
|
||||
if (strcmp(name, "f_locals") == 0)
|
||||
PyFrame_FastToLocals(f);
|
||||
return PyMember_Get((char *)f, frame_memberlist, name);
|
||||
PyFrame_FastToLocals(f);
|
||||
Py_INCREF(f->f_locals);
|
||||
return f->f_locals;
|
||||
}
|
||||
|
||||
static int
|
||||
frame_setattr(PyFrameObject *f, char *name, PyObject *value)
|
||||
{
|
||||
return PyMember_Set((char *)f, frame_memberlist, name, value);
|
||||
}
|
||||
static struct getsetlist frame_getsetlist[] = {
|
||||
{"f_locals", (getter)frame_getlocals, NULL, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
/* Stack frames are allocated and deallocated at a considerable rate.
|
||||
In an attempt to improve the speed of function calls, we maintain a
|
||||
|
@ -177,8 +175,8 @@ PyTypeObject PyFrame_Type = {
|
|||
0,
|
||||
(destructor)frame_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
(getattrfunc)frame_getattr, /* tp_getattr */
|
||||
(setattrfunc)frame_setattr, /* tp_setattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
|
@ -187,13 +185,22 @@ PyTypeObject PyFrame_Type = {
|
|||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
PyObject_GenericSetAttr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)frame_traverse, /* tp_traverse */
|
||||
(inquiry)frame_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
frame_memberlist, /* tp_members */
|
||||
frame_getsetlist, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
};
|
||||
|
||||
PyFrameObject *
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Python.h"
|
||||
#include "compile.h"
|
||||
#include "eval.h"
|
||||
#include "structmember.h"
|
||||
|
||||
PyObject *
|
||||
|
@ -141,9 +142,8 @@ static struct memberlist func_memberlist[] = {
|
|||
};
|
||||
|
||||
static PyObject *
|
||||
func_getattro(PyFunctionObject *op, PyObject *name)
|
||||
func_getattro(PyObject *op, PyObject *name)
|
||||
{
|
||||
PyObject *rtn;
|
||||
char *sname = PyString_AsString(name);
|
||||
|
||||
if (sname[0] != '_' && PyEval_GetRestricted()) {
|
||||
|
@ -152,25 +152,12 @@ func_getattro(PyFunctionObject *op, PyObject *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* no API for PyMember_HasAttr() */
|
||||
rtn = PyMember_Get((char *)op, func_memberlist, sname);
|
||||
|
||||
if (rtn == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
if (op->func_dict != NULL) {
|
||||
rtn = PyDict_GetItem(op->func_dict, name);
|
||||
Py_XINCREF(rtn);
|
||||
}
|
||||
if (rtn == NULL)
|
||||
PyErr_SetObject(PyExc_AttributeError, name);
|
||||
}
|
||||
return rtn;
|
||||
return PyObject_GenericGetAttr(op, name);
|
||||
}
|
||||
|
||||
static int
|
||||
func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
|
||||
func_setattro(PyObject *op, PyObject *name, PyObject *value)
|
||||
{
|
||||
int rtn;
|
||||
char *sname = PyString_AsString(name);
|
||||
|
||||
if (PyEval_GetRestricted()) {
|
||||
|
@ -216,31 +203,7 @@ func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
|
|||
}
|
||||
}
|
||||
|
||||
rtn = PyMember_Set((char *)op, func_memberlist, sname, value);
|
||||
if (rtn < 0 && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
if (op->func_dict == NULL) {
|
||||
/* don't create the dict if we're deleting an
|
||||
* attribute. In that case, we know we'll get an
|
||||
* AttributeError.
|
||||
*/
|
||||
if (value == NULL) {
|
||||
PyErr_SetString(PyExc_AttributeError, sname);
|
||||
return -1;
|
||||
}
|
||||
op->func_dict = PyDict_New();
|
||||
if (op->func_dict == NULL)
|
||||
return -1;
|
||||
}
|
||||
if (value == NULL)
|
||||
rtn = PyDict_DelItem(op->func_dict, name);
|
||||
else
|
||||
rtn = PyDict_SetItem(op->func_dict, name, value);
|
||||
/* transform KeyError into AttributeError */
|
||||
if (rtn < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
|
||||
PyErr_SetString(PyExc_AttributeError, sname);
|
||||
}
|
||||
return rtn;
|
||||
return PyObject_GenericSetAttr(op, name, value);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -314,31 +277,324 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
function_call(PyObject *func, PyObject *arg, PyObject *kw)
|
||||
{
|
||||
PyObject *result;
|
||||
PyObject *argdefs;
|
||||
PyObject **d, **k;
|
||||
int nk, nd;
|
||||
|
||||
argdefs = PyFunction_GET_DEFAULTS(func);
|
||||
if (argdefs != NULL && PyTuple_Check(argdefs)) {
|
||||
d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0);
|
||||
nd = PyTuple_Size(argdefs);
|
||||
}
|
||||
else {
|
||||
d = NULL;
|
||||
nd = 0;
|
||||
}
|
||||
|
||||
if (kw != NULL && PyDict_Check(kw)) {
|
||||
int pos, i;
|
||||
nk = PyDict_Size(kw);
|
||||
k = PyMem_NEW(PyObject *, 2*nk);
|
||||
if (k == NULL) {
|
||||
PyErr_NoMemory();
|
||||
Py_DECREF(arg);
|
||||
return NULL;
|
||||
}
|
||||
pos = i = 0;
|
||||
while (PyDict_Next(kw, &pos, &k[i], &k[i+1]))
|
||||
i += 2;
|
||||
nk = i/2;
|
||||
/* XXX This is broken if the caller deletes dict items! */
|
||||
}
|
||||
else {
|
||||
k = NULL;
|
||||
nk = 0;
|
||||
}
|
||||
|
||||
result = PyEval_EvalCodeEx(
|
||||
(PyCodeObject *)PyFunction_GET_CODE(func),
|
||||
PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
|
||||
&PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
|
||||
k, nk, d, nd,
|
||||
PyFunction_GET_CLOSURE(func));
|
||||
|
||||
if (k != NULL)
|
||||
PyMem_DEL(k);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Bind a function to an object */
|
||||
static PyObject *
|
||||
func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
|
||||
{
|
||||
if (obj == Py_None)
|
||||
obj = NULL;
|
||||
return PyMethod_New(func, obj, type);
|
||||
}
|
||||
|
||||
PyTypeObject PyFunction_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"function",
|
||||
sizeof(PyFunctionObject) + PyGC_HEAD_SIZE,
|
||||
0,
|
||||
(destructor)func_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)func_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
(getattrofunc)func_getattro, /* tp_getattro */
|
||||
(setattrofunc)func_setattro, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)func_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
(destructor)func_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)func_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
function_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
func_getattro, /* tp_getattro */
|
||||
func_setattro, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)func_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
func_memberlist, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
func_descr_get, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */
|
||||
};
|
||||
|
||||
|
||||
/* Class method object */
|
||||
|
||||
/* A class method receives the class as implicit first argument,
|
||||
just like an instance method receives the instance.
|
||||
To declare a class method, use this idiom:
|
||||
|
||||
class C:
|
||||
def f(cls, arg1, arg2, ...): ...
|
||||
f = classmethod(f)
|
||||
|
||||
It can be called either on the class (e.g. C.f()) or on an instance
|
||||
(e.g. C().f()); the instance is ignored except for its class.
|
||||
If a class method is called for a derived class, the derived class
|
||||
object is passed as the implied first argument.
|
||||
|
||||
Class methods are different than C++ or Java static methods.
|
||||
If you want those, see static methods below.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *cm_callable;
|
||||
} classmethod;
|
||||
|
||||
static void
|
||||
cm_dealloc(classmethod *cm)
|
||||
{
|
||||
Py_XDECREF(cm->cm_callable);
|
||||
PyObject_DEL(cm);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
||||
{
|
||||
classmethod *cm = (classmethod *)self;
|
||||
|
||||
if (cm->cm_callable == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"uninitialized classmethod object");
|
||||
return NULL;
|
||||
}
|
||||
return PyMethod_New(cm->cm_callable,
|
||||
type, (PyObject *)(type->ob_type));
|
||||
}
|
||||
|
||||
static int
|
||||
cm_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
classmethod *cm = (classmethod *)self;
|
||||
PyObject *callable;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:callable", &callable))
|
||||
return -1;
|
||||
Py_INCREF(callable);
|
||||
cm->cm_callable = callable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyTypeObject PyClassMethod_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"classmethod",
|
||||
sizeof(classmethod),
|
||||
0,
|
||||
(destructor)cm_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
cm_descr_get, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
cm_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyClassMethod_New(PyObject *callable)
|
||||
{
|
||||
classmethod *cm = (classmethod *)
|
||||
PyType_GenericAlloc(&PyClassMethod_Type, 0);
|
||||
if (cm != NULL) {
|
||||
Py_INCREF(callable);
|
||||
cm->cm_callable = callable;
|
||||
}
|
||||
return (PyObject *)cm;
|
||||
}
|
||||
|
||||
|
||||
/* Static method object */
|
||||
|
||||
/* A static method does not receive an implicit first argument.
|
||||
To declare a static method, use this idiom:
|
||||
|
||||
class C:
|
||||
def f(arg1, arg2, ...): ...
|
||||
f = staticmethod(f)
|
||||
|
||||
It can be called either on the class (e.g. C.f()) or on an instance
|
||||
(e.g. C().f()); the instance is ignored except for its class.
|
||||
|
||||
Static methods in Python are similar to those found in Java or C++.
|
||||
For a more advanced concept, see class methods above.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *sm_callable;
|
||||
} staticmethod;
|
||||
|
||||
static void
|
||||
sm_dealloc(staticmethod *sm)
|
||||
{
|
||||
Py_XDECREF(sm->sm_callable);
|
||||
PyObject_DEL(sm);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
sm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
||||
{
|
||||
staticmethod *sm = (staticmethod *)self;
|
||||
|
||||
if (sm->sm_callable == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"uninitialized staticmethod object");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(sm->sm_callable);
|
||||
return sm->sm_callable;
|
||||
}
|
||||
|
||||
static int
|
||||
sm_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
staticmethod *sm = (staticmethod *)self;
|
||||
PyObject *callable;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:callable", &callable))
|
||||
return -1;
|
||||
Py_INCREF(callable);
|
||||
sm->sm_callable = callable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyTypeObject PyStaticMethod_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"staticmethod",
|
||||
sizeof(staticmethod),
|
||||
0,
|
||||
(destructor)sm_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
sm_descr_get, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
sm_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyStaticMethod_New(PyObject *callable)
|
||||
{
|
||||
staticmethod *sm = (staticmethod *)
|
||||
PyType_GenericAlloc(&PyStaticMethod_Type, 0);
|
||||
if (sm != NULL) {
|
||||
Py_INCREF(callable);
|
||||
sm->sm_callable = callable;
|
||||
}
|
||||
return (PyObject *)sm;
|
||||
}
|
||||
|
|
|
@ -742,6 +742,41 @@ int_hex(PyIntObject *v)
|
|||
return PyString_FromString(buf);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
int_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *x = NULL;
|
||||
int base = -909;
|
||||
static char *kwlist[] = {"x", "base", 0};
|
||||
|
||||
assert(type == &PyInt_Type);
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:int", kwlist,
|
||||
&x, &base))
|
||||
return NULL;
|
||||
if (x == NULL)
|
||||
return PyInt_FromLong(0L);
|
||||
if (base == -909)
|
||||
return PyNumber_Int(x);
|
||||
if (PyString_Check(x))
|
||||
return PyInt_FromString(PyString_AS_STRING(x), NULL, base);
|
||||
if (PyUnicode_Check(x))
|
||||
return PyInt_FromUnicode(PyUnicode_AS_UNICODE(x),
|
||||
PyUnicode_GET_SIZE(x),
|
||||
base);
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"int() can't convert non-string with explicit base");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char int_doc[] =
|
||||
"int(x[, base]) -> integer\n\
|
||||
\n\
|
||||
Convert a string or number to an integer, if possible. A floating point\n\
|
||||
argument will be truncated towards zero (this does not include a string\n\
|
||||
representation of a floating point number!) When converting a string, use\n\
|
||||
the optional base. It is an error to supply a base when converting a\n\
|
||||
non-string.";
|
||||
|
||||
static PyNumberMethods int_as_number = {
|
||||
(binaryfunc)int_add, /*nb_add*/
|
||||
(binaryfunc)int_sub, /*nb_subtract*/
|
||||
|
@ -785,22 +820,40 @@ PyTypeObject PyInt_Type = {
|
|||
"int",
|
||||
sizeof(PyIntObject),
|
||||
0,
|
||||
(destructor)int_dealloc, /*tp_dealloc*/
|
||||
(printfunc)int_print, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
(cmpfunc)int_compare, /*tp_compare*/
|
||||
(reprfunc)int_repr, /*tp_repr*/
|
||||
&int_as_number, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
(hashfunc)int_hash, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
|
||||
(destructor)int_dealloc, /* tp_dealloc */
|
||||
(printfunc)int_print, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
(cmpfunc)int_compare, /* tp_compare */
|
||||
(reprfunc)int_repr, /* tp_repr */
|
||||
&int_as_number, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)int_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
|
||||
int_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
int_new, /* tp_new */
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -96,12 +96,6 @@ static PyMethodDef iter_methods[] = {
|
|||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
iter_getattr(seqiterobject *it, char *name)
|
||||
{
|
||||
return Py_FindMethod(iter_methods, (PyObject *)it, name);
|
||||
}
|
||||
|
||||
PyTypeObject PySeqIter_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /* ob_size */
|
||||
|
@ -111,7 +105,7 @@ PyTypeObject PySeqIter_Type = {
|
|||
/* methods */
|
||||
(destructor)iter_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
(getattrfunc)iter_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
|
@ -121,7 +115,7 @@ PyTypeObject PySeqIter_Type = {
|
|||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
|
@ -132,6 +126,13 @@ PyTypeObject PySeqIter_Type = {
|
|||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)iter_getiter, /* tp_iter */
|
||||
(iternextfunc)iter_iternext, /* tp_iternext */
|
||||
iter_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
};
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
@ -197,12 +198,6 @@ static PyMethodDef calliter_methods[] = {
|
|||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
calliter_getattr(calliterobject *it, char *name)
|
||||
{
|
||||
return Py_FindMethod(calliter_methods, (PyObject *)it, name);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
calliter_iternext(calliterobject *it)
|
||||
{
|
||||
|
@ -228,7 +223,7 @@ PyTypeObject PyCallIter_Type = {
|
|||
/* methods */
|
||||
(destructor)calliter_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
(getattrfunc)calliter_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
|
@ -238,7 +233,7 @@ PyTypeObject PyCallIter_Type = {
|
|||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
|
@ -249,4 +244,11 @@ PyTypeObject PyCallIter_Type = {
|
|||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)iter_getiter, /* tp_iter */
|
||||
(iternextfunc)calliter_iternext, /* tp_iternext */
|
||||
calliter_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
};
|
||||
|
|
|
@ -523,6 +523,10 @@ list_ass_slice(PyListObject *a, int ilow, int ihigh, PyObject *v)
|
|||
Py_XDECREF(*p);
|
||||
PyMem_DEL(recycle);
|
||||
}
|
||||
if (a->ob_size == 0 && a->ob_item != NULL) {
|
||||
PyMem_FREE(a->ob_item);
|
||||
a->ob_item = NULL;
|
||||
}
|
||||
return 0;
|
||||
#undef b
|
||||
}
|
||||
|
@ -1289,16 +1293,18 @@ listsort(PyListObject *self, PyObject *args)
|
|||
{
|
||||
int err;
|
||||
PyObject *compare = NULL;
|
||||
PyTypeObject *savetype;
|
||||
|
||||
if (args != NULL) {
|
||||
if (!PyArg_ParseTuple(args, "|O:sort", &compare))
|
||||
return NULL;
|
||||
}
|
||||
savetype = self->ob_type;
|
||||
self->ob_type = &immutable_list_type;
|
||||
err = samplesortslice(self->ob_item,
|
||||
self->ob_item + self->ob_size,
|
||||
compare);
|
||||
self->ob_type = &PyList_Type;
|
||||
self->ob_type = savetype;
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
Py_INCREF(Py_None);
|
||||
|
@ -1541,6 +1547,100 @@ list_richcompare(PyObject *v, PyObject *w, int op)
|
|||
return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
|
||||
}
|
||||
|
||||
/* Adapted from newer code by Tim */
|
||||
static int
|
||||
list_fill(PyListObject *result, PyObject *v)
|
||||
{
|
||||
PyObject *it; /* iter(v) */
|
||||
int n; /* guess for result list size */
|
||||
int i;
|
||||
|
||||
n = result->ob_size;
|
||||
|
||||
/* Special-case list(a_list), for speed. */
|
||||
if (PyList_Check(v)) {
|
||||
if (v == (PyObject *)result)
|
||||
return 0; /* source is destination, we're done */
|
||||
return list_ass_slice(result, 0, n, v);
|
||||
}
|
||||
|
||||
/* Empty previous contents */
|
||||
if (n != 0) {
|
||||
if (list_ass_slice(result, 0, n, (PyObject *)NULL) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get iterator. There may be some low-level efficiency to be gained
|
||||
* by caching the tp_iternext slot instead of using PyIter_Next()
|
||||
* later, but premature optimization is the root etc.
|
||||
*/
|
||||
it = PyObject_GetIter(v);
|
||||
if (it == NULL)
|
||||
return -1;
|
||||
|
||||
/* Guess a result list size. */
|
||||
n = -1; /* unknown */
|
||||
if (PySequence_Check(v) &&
|
||||
v->ob_type->tp_as_sequence->sq_length) {
|
||||
n = PySequence_Size(v);
|
||||
if (n < 0)
|
||||
PyErr_Clear();
|
||||
}
|
||||
if (n < 0)
|
||||
n = 8; /* arbitrary */
|
||||
NRESIZE(result->ob_item, PyObject*, n);
|
||||
if (result->ob_item == NULL)
|
||||
goto error;
|
||||
for (i = 0; i < n; i++)
|
||||
result->ob_item[i] = NULL;
|
||||
result->ob_size = n;
|
||||
|
||||
/* Run iterator to exhaustion. */
|
||||
for (i = 0; ; i++) {
|
||||
PyObject *item = PyIter_Next(it);
|
||||
if (item == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
if (i < n)
|
||||
PyList_SET_ITEM(result, i, item); /* steals ref */
|
||||
else {
|
||||
int status = ins1(result, result->ob_size, item);
|
||||
Py_DECREF(item); /* append creates a new ref */
|
||||
if (status < 0)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cut back result list if initial guess was too large. */
|
||||
if (i < n && result != NULL) {
|
||||
if (list_ass_slice(result, i, n, (PyObject *)NULL) != 0)
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(it);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
Py_DECREF(it);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
list_init(PyListObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *arg = NULL;
|
||||
static char *kwlist[] = {"sequence", 0};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:list", kwlist, &arg))
|
||||
return -1;
|
||||
if (arg != NULL)
|
||||
return list_fill(self, arg);
|
||||
if (self->ob_size > 0)
|
||||
return list_ass_slice(self, 0, self->ob_size, (PyObject*)NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char append_doc[] =
|
||||
"L.append(object) -- append object to end";
|
||||
static char extend_doc[] =
|
||||
|
@ -1573,12 +1673,6 @@ static PyMethodDef list_methods[] = {
|
|||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
list_getattr(PyListObject *f, char *name)
|
||||
{
|
||||
return Py_FindMethod(list_methods, (PyObject *)f, name);
|
||||
}
|
||||
|
||||
static PySequenceMethods list_as_sequence = {
|
||||
(inquiry)list_length, /* sq_length */
|
||||
(binaryfunc)list_concat, /* sq_concat */
|
||||
|
@ -1592,6 +1686,10 @@ static PySequenceMethods list_as_sequence = {
|
|||
(intargfunc)list_inplace_repeat, /* sq_inplace_repeat */
|
||||
};
|
||||
|
||||
static char list_doc[] =
|
||||
"list() -> new list\n"
|
||||
"list(sequence) -> new list initialized from sequence's items";
|
||||
|
||||
PyTypeObject PyList_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
|
@ -1600,7 +1698,7 @@ PyTypeObject PyList_Type = {
|
|||
0,
|
||||
(destructor)list_dealloc, /* tp_dealloc */
|
||||
(printfunc)list_print, /* tp_print */
|
||||
(getattrfunc)list_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)list_repr, /* tp_repr */
|
||||
|
@ -1610,14 +1708,29 @@ PyTypeObject PyList_Type = {
|
|||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
|
||||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
list_doc, /* tp_doc */
|
||||
(traverseproc)list_traverse, /* tp_traverse */
|
||||
(inquiry)list_clear, /* tp_clear */
|
||||
list_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
list_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)list_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
};
|
||||
|
||||
|
||||
|
@ -1646,12 +1759,6 @@ static PyMethodDef immutable_list_methods[] = {
|
|||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
immutable_list_getattr(PyListObject *f, char *name)
|
||||
{
|
||||
return Py_FindMethod(immutable_list_methods, (PyObject *)f, name);
|
||||
}
|
||||
|
||||
static int
|
||||
immutable_list_ass(void)
|
||||
{
|
||||
|
@ -1678,7 +1785,7 @@ static PyTypeObject immutable_list_type = {
|
|||
0,
|
||||
0, /* Cannot happen */ /* tp_dealloc */
|
||||
(printfunc)list_print, /* tp_print */
|
||||
(getattrfunc)immutable_list_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* Won't be called */ /* tp_compare */
|
||||
(reprfunc)list_repr, /* tp_repr */
|
||||
|
@ -1688,13 +1795,24 @@ static PyTypeObject immutable_list_type = {
|
|||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
list_doc, /* tp_doc */
|
||||
(traverseproc)list_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
list_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
immutable_list_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_init */
|
||||
/* NOTE: This is *not* the standard list_type struct! */
|
||||
};
|
||||
|
|
|
@ -2031,6 +2031,43 @@ long_hex(PyObject *v)
|
|||
return long_format(v, 16, 1);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *x = NULL;
|
||||
int base = -909; /* unlikely! */
|
||||
static char *kwlist[] = {"x", "base", 0};
|
||||
|
||||
assert(type == &PyLong_Type);
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:long", kwlist,
|
||||
&x, &base))
|
||||
return NULL;
|
||||
if (x == NULL)
|
||||
return PyLong_FromLong(0L);
|
||||
if (base == -909)
|
||||
return PyNumber_Long(x);
|
||||
else if (PyString_Check(x))
|
||||
return PyLong_FromString(PyString_AS_STRING(x), NULL, base);
|
||||
else if (PyUnicode_Check(x))
|
||||
return PyLong_FromUnicode(PyUnicode_AS_UNICODE(x),
|
||||
PyUnicode_GET_SIZE(x),
|
||||
base);
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"long() can't convert non-string with explicit base");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static char long_doc[] =
|
||||
"long(x[, base]) -> integer\n\
|
||||
\n\
|
||||
Convert a string or number to a long integer, if possible. A floating\n\
|
||||
point argument will be truncated towards zero (this does not include a\n\
|
||||
string representation of a floating point number!) When converting a\n\
|
||||
string, use the optional base. It is an error to supply a base when\n\
|
||||
converting a non-string.";
|
||||
|
||||
static PyNumberMethods long_as_number = {
|
||||
(binaryfunc) long_add, /*nb_add*/
|
||||
(binaryfunc) long_sub, /*nb_subtract*/
|
||||
|
@ -2070,24 +2107,42 @@ static PyNumberMethods long_as_number = {
|
|||
|
||||
PyTypeObject PyLong_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"long int",
|
||||
sizeof(PyLongObject) - sizeof(digit),
|
||||
sizeof(digit),
|
||||
(destructor)long_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
(cmpfunc)long_compare, /*tp_compare*/
|
||||
(reprfunc)long_repr, /*tp_repr*/
|
||||
&long_as_number, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
(hashfunc)long_hash, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
(reprfunc)long_str, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_CHECKTYPES /*tp_flags*/
|
||||
0, /* ob_size */
|
||||
"long", /* tp_name */
|
||||
sizeof(PyLongObject) - sizeof(digit), /* tp_basicsize */
|
||||
sizeof(digit), /* tp_itemsize */
|
||||
(destructor)long_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
(cmpfunc)long_compare, /* tp_compare */
|
||||
(reprfunc)long_repr, /* tp_repr */
|
||||
&long_as_number, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)long_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
(reprfunc)long_str, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
|
||||
long_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
long_new, /* tp_new */
|
||||
};
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include "Python.h"
|
||||
|
||||
#include "token.h"
|
||||
|
||||
static PyCFunctionObject *free_list = NULL;
|
||||
|
||||
PyObject *
|
||||
|
@ -69,6 +67,23 @@ meth_dealloc(PyCFunctionObject *m)
|
|||
free_list = m;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_get__doc__(PyCFunctionObject *m, void *closure)
|
||||
{
|
||||
char *doc = m->m_ml->ml_doc;
|
||||
|
||||
if (doc != NULL)
|
||||
return PyString_FromString(doc);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_get__name__(PyCFunctionObject *m, void *closure)
|
||||
{
|
||||
return PyString_FromString(m->m_ml->ml_name);
|
||||
}
|
||||
|
||||
static int
|
||||
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
|
||||
{
|
||||
|
@ -79,39 +94,28 @@ meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
meth_getattr(PyCFunctionObject *m, char *name)
|
||||
meth_get__self__(PyCFunctionObject *m, void *closure)
|
||||
{
|
||||
if (strcmp(name, "__name__") == 0) {
|
||||
return PyString_FromString(m->m_ml->ml_name);
|
||||
PyObject *self;
|
||||
if (PyEval_GetRestricted()) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"method.__self__ not accessible in restricted mode");
|
||||
return NULL;
|
||||
}
|
||||
if (strcmp(name, "__doc__") == 0) {
|
||||
char *doc = m->m_ml->ml_doc;
|
||||
if (doc != NULL)
|
||||
return PyString_FromString(doc);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
if (strcmp(name, "__self__") == 0) {
|
||||
PyObject *self;
|
||||
if (PyEval_GetRestricted()) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"method.__self__ not accessible in restricted mode");
|
||||
return NULL;
|
||||
}
|
||||
self = m->m_self;
|
||||
if (self == NULL)
|
||||
self = Py_None;
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
if (strcmp(name, "__members__") == 0) {
|
||||
return Py_BuildValue("[sss]",
|
||||
"__doc__", "__name__", "__self__");
|
||||
}
|
||||
PyErr_SetString(PyExc_AttributeError, name);
|
||||
return NULL;
|
||||
self = m->m_self;
|
||||
if (self == NULL)
|
||||
self = Py_None;
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
static struct getsetlist meth_getsets [] = {
|
||||
{"__doc__", (getter)meth_get__doc__, NULL, NULL},
|
||||
{"__name__", (getter)meth_get__name__, NULL, NULL},
|
||||
{"__self__", (getter)meth_get__self__, NULL, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
meth_repr(PyCFunctionObject *m)
|
||||
{
|
||||
|
@ -159,6 +163,41 @@ meth_hash(PyCFunctionObject *a)
|
|||
return x;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_call(PyObject *func, PyObject *arg, PyObject *kw)
|
||||
{
|
||||
PyCFunctionObject* f = (PyCFunctionObject*)func;
|
||||
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
|
||||
PyObject *self = PyCFunction_GET_SELF(func);
|
||||
int flags = PyCFunction_GET_FLAGS(func);
|
||||
|
||||
if (flags & METH_KEYWORDS) {
|
||||
return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
|
||||
}
|
||||
if (kw != NULL && PyDict_Size(kw) != 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes no keyword arguments",
|
||||
f->m_ml->ml_name);
|
||||
return NULL;
|
||||
}
|
||||
if (flags & METH_VARARGS) {
|
||||
return (*meth)(self, arg);
|
||||
}
|
||||
if (!(flags & METH_VARARGS)) {
|
||||
/* the really old style */
|
||||
int size = PyTuple_GET_SIZE(arg);
|
||||
if (size == 1)
|
||||
arg = PyTuple_GET_ITEM(arg, 0);
|
||||
else if (size == 0)
|
||||
arg = NULL;
|
||||
return (*meth)(self, arg);
|
||||
}
|
||||
/* should never get here ??? */
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PyTypeObject PyCFunction_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
|
@ -167,7 +206,7 @@ PyTypeObject PyCFunction_Type = {
|
|||
0,
|
||||
(destructor)meth_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
(getattrfunc)meth_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
(cmpfunc)meth_compare, /* tp_compare */
|
||||
(reprfunc)meth_repr, /* tp_repr */
|
||||
|
@ -175,14 +214,24 @@ PyTypeObject PyCFunction_Type = {
|
|||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)meth_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
meth_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)meth_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
meth_getsets, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
};
|
||||
|
||||
/* List all methods in a chain -- helper for findmethodinchain */
|
||||
|
|
|
@ -2,12 +2,18 @@
|
|||
/* Module object implementation */
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *md_dict;
|
||||
} PyModuleObject;
|
||||
|
||||
struct memberlist module_members[] = {
|
||||
{"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY},
|
||||
{0}
|
||||
};
|
||||
|
||||
PyObject *
|
||||
PyModule_New(char *name)
|
||||
{
|
||||
|
@ -128,6 +134,15 @@ _PyModule_Clear(PyObject *m)
|
|||
|
||||
/* Methods */
|
||||
|
||||
static int
|
||||
module_init(PyModuleObject *m, PyObject *args, PyObject *kw)
|
||||
{
|
||||
m->md_dict = PyDict_New();
|
||||
if (m->md_dict == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
module_dealloc(PyModuleObject *m)
|
||||
{
|
||||
|
@ -161,59 +176,6 @@ module_repr(PyModuleObject *m)
|
|||
return PyString_FromString(buf);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
module_getattro(PyModuleObject *m, PyObject *name)
|
||||
{
|
||||
PyObject *res;
|
||||
char *sname = PyString_AsString(name);
|
||||
|
||||
if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
|
||||
Py_INCREF(m->md_dict);
|
||||
return m->md_dict;
|
||||
}
|
||||
res = PyDict_GetItem(m->md_dict, name);
|
||||
if (res == NULL) {
|
||||
char *modname = PyModule_GetName((PyObject *)m);
|
||||
if (modname == NULL) {
|
||||
PyErr_Clear();
|
||||
modname = "?";
|
||||
}
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%.50s' module has no attribute '%.400s'",
|
||||
modname, sname);
|
||||
}
|
||||
else
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
module_setattro(PyModuleObject *m, PyObject *name, PyObject *v)
|
||||
{
|
||||
char *sname = PyString_AsString(name);
|
||||
if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"read-only special attribute");
|
||||
return -1;
|
||||
}
|
||||
if (v == NULL) {
|
||||
int rv = PyDict_DelItem(m->md_dict, name);
|
||||
if (rv < 0) {
|
||||
char *modname = PyModule_GetName((PyObject *)m);
|
||||
if (modname == NULL) {
|
||||
PyErr_Clear();
|
||||
modname = "?";
|
||||
}
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%.50s' module has no attribute '%.400s'",
|
||||
modname, sname);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
return PyDict_SetItem(m->md_dict, name, v);
|
||||
}
|
||||
|
||||
/* We only need a traverse function, no clear function: If the module
|
||||
is in a cycle, md_dict will be cleared as well, which will break
|
||||
the cycle. */
|
||||
|
@ -229,24 +191,41 @@ PyTypeObject PyModule_Type = {
|
|||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /* ob_size */
|
||||
"module", /* tp_name */
|
||||
sizeof(PyModuleObject) + PyGC_HEAD_SIZE,/* tp_size */
|
||||
sizeof(PyModuleObject) + PyGC_HEAD_SIZE, /* tp_size */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)module_dealloc, /* tp_dealloc */
|
||||
(destructor)module_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)module_repr, /* tp_repr */
|
||||
(reprfunc)module_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
(getattrofunc)module_getattro, /* tp_getattro */
|
||||
(setattrofunc)module_setattro, /* tp_setattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
PyObject_GenericSetAttr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC |
|
||||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)module_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
module_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
offsetof(PyModuleObject, md_dict), /* tp_dictoffset */
|
||||
(initproc)module_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
};
|
||||
|
|
293
Objects/object.c
293
Objects/object.c
|
@ -32,7 +32,7 @@ dump_counts(void)
|
|||
|
||||
for (tp = type_list; tp; tp = tp->tp_next)
|
||||
fprintf(stderr, "%s alloc'd: %d, freed: %d, max in use: %d\n",
|
||||
tp->tp_name, tp->tp_alloc, tp->tp_free,
|
||||
tp->tp_name, tp->tp_allocs, tp->tp_frees,
|
||||
tp->tp_maxalloc);
|
||||
fprintf(stderr, "fast tuple allocs: %d, empty: %d\n",
|
||||
fast_tuple_allocs, tuple_zero_allocs);
|
||||
|
@ -53,8 +53,8 @@ get_counts(void)
|
|||
if (result == NULL)
|
||||
return NULL;
|
||||
for (tp = type_list; tp; tp = tp->tp_next) {
|
||||
v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_alloc,
|
||||
tp->tp_free, tp->tp_maxalloc);
|
||||
v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_allocs,
|
||||
tp->tp_frees, tp->tp_maxalloc);
|
||||
if (v == NULL) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
|
@ -72,16 +72,16 @@ get_counts(void)
|
|||
void
|
||||
inc_count(PyTypeObject *tp)
|
||||
{
|
||||
if (tp->tp_alloc == 0) {
|
||||
if (tp->tp_allocs == 0) {
|
||||
/* first time; insert in linked list */
|
||||
if (tp->tp_next != NULL) /* sanity check */
|
||||
Py_FatalError("XXX inc_count sanity check");
|
||||
tp->tp_next = type_list;
|
||||
type_list = tp;
|
||||
}
|
||||
tp->tp_alloc++;
|
||||
if (tp->tp_alloc - tp->tp_free > tp->tp_maxalloc)
|
||||
tp->tp_maxalloc = tp->tp_alloc - tp->tp_free;
|
||||
tp->tp_allocs++;
|
||||
if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc)
|
||||
tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -93,10 +93,8 @@ PyObject_Init(PyObject *op, PyTypeObject *tp)
|
|||
"NULL object passed to PyObject_Init");
|
||||
return op;
|
||||
}
|
||||
#ifdef WITH_CYCLE_GC
|
||||
if (PyType_IS_GC(tp))
|
||||
op = (PyObject *) PyObject_FROM_GC(op);
|
||||
#endif
|
||||
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
|
||||
op->ob_type = tp;
|
||||
_Py_NewReference(op);
|
||||
|
@ -111,10 +109,8 @@ PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, int size)
|
|||
"NULL object passed to PyObject_InitVar");
|
||||
return op;
|
||||
}
|
||||
#ifdef WITH_CYCLE_GC
|
||||
if (PyType_IS_GC(tp))
|
||||
op = (PyVarObject *) PyObject_FROM_GC(op);
|
||||
#endif
|
||||
/* Any changes should be reflected in PyObject_INIT_VAR */
|
||||
op->ob_size = size;
|
||||
op->ob_type = tp;
|
||||
|
@ -129,10 +125,8 @@ _PyObject_New(PyTypeObject *tp)
|
|||
op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
|
||||
if (op == NULL)
|
||||
return PyErr_NoMemory();
|
||||
#ifdef WITH_CYCLE_GC
|
||||
if (PyType_IS_GC(tp))
|
||||
op = (PyObject *) PyObject_FROM_GC(op);
|
||||
#endif
|
||||
return PyObject_INIT(op, tp);
|
||||
}
|
||||
|
||||
|
@ -143,21 +137,17 @@ _PyObject_NewVar(PyTypeObject *tp, int size)
|
|||
op = (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size));
|
||||
if (op == NULL)
|
||||
return (PyVarObject *)PyErr_NoMemory();
|
||||
#ifdef WITH_CYCLE_GC
|
||||
if (PyType_IS_GC(tp))
|
||||
op = (PyVarObject *) PyObject_FROM_GC(op);
|
||||
#endif
|
||||
return PyObject_INIT_VAR(op, tp, size);
|
||||
}
|
||||
|
||||
void
|
||||
_PyObject_Del(PyObject *op)
|
||||
{
|
||||
#ifdef WITH_CYCLE_GC
|
||||
if (op && PyType_IS_GC(op->ob_type)) {
|
||||
op = (PyObject *) PyObject_AS_GC(op);
|
||||
}
|
||||
#endif
|
||||
PyObject_FREE(op);
|
||||
}
|
||||
|
||||
|
@ -994,26 +984,16 @@ PyObject_Hash(PyObject *v)
|
|||
PyObject *
|
||||
PyObject_GetAttrString(PyObject *v, char *name)
|
||||
{
|
||||
if (v->ob_type->tp_getattro != NULL) {
|
||||
PyObject *w, *res;
|
||||
w = PyString_InternFromString(name);
|
||||
if (w == NULL)
|
||||
return NULL;
|
||||
res = (*v->ob_type->tp_getattro)(v, w);
|
||||
Py_XDECREF(w);
|
||||
return res;
|
||||
}
|
||||
PyObject *w, *res;
|
||||
|
||||
if (v->ob_type->tp_getattr == NULL) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%.50s' object has no attribute '%.400s'",
|
||||
v->ob_type->tp_name,
|
||||
name);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
if (v->ob_type->tp_getattr != NULL)
|
||||
return (*v->ob_type->tp_getattr)(v, name);
|
||||
}
|
||||
w = PyString_InternFromString(name);
|
||||
if (w == NULL)
|
||||
return NULL;
|
||||
res = PyObject_GetAttr(v, w);
|
||||
Py_XDECREF(w);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1031,34 +1011,24 @@ PyObject_HasAttrString(PyObject *v, char *name)
|
|||
int
|
||||
PyObject_SetAttrString(PyObject *v, char *name, PyObject *w)
|
||||
{
|
||||
if (v->ob_type->tp_setattro != NULL) {
|
||||
PyObject *s;
|
||||
int res;
|
||||
s = PyString_InternFromString(name);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
res = (*v->ob_type->tp_setattro)(v, s, w);
|
||||
Py_XDECREF(s);
|
||||
return res;
|
||||
}
|
||||
PyObject *s;
|
||||
int res;
|
||||
|
||||
if (v->ob_type->tp_setattr == NULL) {
|
||||
if (v->ob_type->tp_getattr == NULL)
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"attribute-less object (assign or del)");
|
||||
else
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"object has read-only attributes");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (v->ob_type->tp_setattr != NULL)
|
||||
return (*v->ob_type->tp_setattr)(v, name, w);
|
||||
}
|
||||
s = PyString_InternFromString(name);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
res = PyObject_SetAttr(v, s, w);
|
||||
Py_XDECREF(s);
|
||||
return res;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyObject_GetAttr(PyObject *v, PyObject *name)
|
||||
{
|
||||
PyTypeObject *tp = v->ob_type;
|
||||
|
||||
/* The Unicode to string conversion is done here because the
|
||||
existing tp_getattro slots expect a string object as name
|
||||
and we wouldn't want to break those. */
|
||||
|
@ -1067,16 +1037,19 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
|
|||
if (name == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyString_Check(name)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"attribute name must be string");
|
||||
return NULL;
|
||||
}
|
||||
if (v->ob_type->tp_getattro != NULL)
|
||||
return (*v->ob_type->tp_getattro)(v, name);
|
||||
else
|
||||
return PyObject_GetAttrString(v, PyString_AS_STRING(name));
|
||||
if (tp->tp_getattro != NULL)
|
||||
return (*tp->tp_getattro)(v, name);
|
||||
if (tp->tp_getattr != NULL)
|
||||
return (*tp->tp_getattr)(v, PyString_AS_STRING(name));
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%.50s' object has no attribute '%.400s'",
|
||||
tp->tp_name, PyString_AS_STRING(name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1094,6 +1067,7 @@ PyObject_HasAttr(PyObject *v, PyObject *name)
|
|||
int
|
||||
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
|
||||
{
|
||||
PyTypeObject *tp = v->ob_type;
|
||||
int err;
|
||||
|
||||
/* The Unicode to string conversion is done here because the
|
||||
|
@ -1104,25 +1078,182 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
|
|||
if (name == NULL)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
Py_INCREF(name);
|
||||
|
||||
if (!PyString_Check(name)){
|
||||
else if (!PyString_Check(name)){
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"attribute name must be string");
|
||||
err = -1;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
PyString_InternInPlace(&name);
|
||||
if (v->ob_type->tp_setattro != NULL)
|
||||
err = (*v->ob_type->tp_setattro)(v, name, value);
|
||||
else
|
||||
err = PyObject_SetAttrString(v,
|
||||
PyString_AS_STRING(name), value);
|
||||
else
|
||||
Py_INCREF(name);
|
||||
|
||||
PyString_InternInPlace(&name);
|
||||
if (tp->tp_setattro != NULL) {
|
||||
err = (*tp->tp_setattro)(v, name, value);
|
||||
Py_DECREF(name);
|
||||
return err;
|
||||
}
|
||||
if (tp->tp_setattr != NULL) {
|
||||
err = (*tp->tp_setattr)(v, PyString_AS_STRING(name), value);
|
||||
Py_DECREF(name);
|
||||
return err;
|
||||
}
|
||||
|
||||
Py_DECREF(name);
|
||||
return err;
|
||||
if (tp->tp_getattr == NULL && tp->tp_getattro == NULL)
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"'%.100s' object has no attributes "
|
||||
"(%s .%.100s)",
|
||||
tp->tp_name,
|
||||
value==NULL ? "del" : "assign to",
|
||||
PyString_AS_STRING(name));
|
||||
else
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"'%.100s' object has only read-only attributes "
|
||||
"(%s .%.100s)",
|
||||
tp->tp_name,
|
||||
value==NULL ? "del" : "assign to",
|
||||
PyString_AS_STRING(name));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Helper to get a pointer to an object's __dict__ slot, if any */
|
||||
|
||||
PyObject **
|
||||
_PyObject_GetDictPtr(PyObject *obj)
|
||||
{
|
||||
#define PTRSIZE (sizeof(PyObject *))
|
||||
|
||||
long dictoffset;
|
||||
PyTypeObject *tp = obj->ob_type;
|
||||
|
||||
if (!(tp->tp_flags & Py_TPFLAGS_HAVE_CLASS))
|
||||
return NULL;
|
||||
dictoffset = tp->tp_dictoffset;
|
||||
if (dictoffset == 0)
|
||||
return NULL;
|
||||
if (dictoffset < 0) {
|
||||
dictoffset += PyType_BASICSIZE(tp);
|
||||
assert(dictoffset > 0); /* Sanity check */
|
||||
if (tp->tp_itemsize > 0) {
|
||||
int n = ((PyVarObject *)obj)->ob_size;
|
||||
if (n > 0) {
|
||||
dictoffset += tp->tp_itemsize * n;
|
||||
/* Round up, if necessary */
|
||||
if (tp->tp_itemsize % PTRSIZE != 0) {
|
||||
dictoffset += PTRSIZE - 1;
|
||||
dictoffset /= PTRSIZE;
|
||||
dictoffset *= PTRSIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (PyObject **) ((char *)obj + dictoffset);
|
||||
}
|
||||
|
||||
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */
|
||||
|
||||
PyObject *
|
||||
PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
|
||||
{
|
||||
PyTypeObject *tp = obj->ob_type;
|
||||
PyObject *descr;
|
||||
descrgetfunc f;
|
||||
PyObject **dictptr;
|
||||
|
||||
if (tp->tp_dict == NULL) {
|
||||
if (PyType_InitDict(tp) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
descr = _PyType_Lookup(tp, name);
|
||||
f = NULL;
|
||||
if (descr != NULL) {
|
||||
f = descr->ob_type->tp_descr_get;
|
||||
if (f != NULL && PyDescr_IsData(descr))
|
||||
return f(descr, obj, (PyObject *)obj->ob_type);
|
||||
}
|
||||
|
||||
dictptr = _PyObject_GetDictPtr(obj);
|
||||
if (dictptr != NULL) {
|
||||
PyObject *dict = *dictptr;
|
||||
if (dict != NULL) {
|
||||
PyObject *res = PyDict_GetItem(dict, name);
|
||||
if (res != NULL) {
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (f != NULL)
|
||||
return f(descr, obj, (PyObject *)obj->ob_type);
|
||||
|
||||
if (descr != NULL) {
|
||||
Py_INCREF(descr);
|
||||
return descr;
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%.50s' object has no attribute '%.400s'",
|
||||
tp->tp_name, PyString_AS_STRING(name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
|
||||
{
|
||||
PyTypeObject *tp = obj->ob_type;
|
||||
PyObject *descr;
|
||||
descrsetfunc f;
|
||||
PyObject **dictptr;
|
||||
|
||||
if (tp->tp_dict == NULL) {
|
||||
if (PyType_InitDict(tp) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
descr = _PyType_Lookup(tp, name);
|
||||
f = NULL;
|
||||
if (descr != NULL) {
|
||||
f = descr->ob_type->tp_descr_set;
|
||||
if (f != NULL && PyDescr_IsData(descr))
|
||||
return f(descr, obj, value);
|
||||
}
|
||||
|
||||
dictptr = _PyObject_GetDictPtr(obj);
|
||||
if (dictptr != NULL) {
|
||||
PyObject *dict = *dictptr;
|
||||
if (dict == NULL && value != NULL) {
|
||||
dict = PyDict_New();
|
||||
if (dict == NULL)
|
||||
return -1;
|
||||
*dictptr = dict;
|
||||
}
|
||||
if (dict != NULL) {
|
||||
int res;
|
||||
if (value == NULL)
|
||||
res = PyDict_DelItem(dict, name);
|
||||
else
|
||||
res = PyDict_SetItem(dict, name, value);
|
||||
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
|
||||
PyErr_SetObject(PyExc_AttributeError, name);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (f != NULL)
|
||||
return f(descr, obj, value);
|
||||
|
||||
if (descr == NULL) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%.50s' object has no attribute '%.400s'",
|
||||
tp->tp_name, PyString_AS_STRING(name));
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%.50s' object attribute '%.400s' is read-only",
|
||||
tp->tp_name, PyString_AS_STRING(name));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Test a value used as condition, e.g., in a for or if statement.
|
||||
|
@ -1218,12 +1349,6 @@ PyCallable_Check(PyObject *x)
|
|||
{
|
||||
if (x == NULL)
|
||||
return 0;
|
||||
if (x->ob_type->tp_call != NULL ||
|
||||
PyFunction_Check(x) ||
|
||||
PyMethod_Check(x) ||
|
||||
PyCFunction_Check(x) ||
|
||||
PyClass_Check(x))
|
||||
return 1;
|
||||
if (PyInstance_Check(x)) {
|
||||
PyObject *call = PyObject_GetAttrString(x, "__call__");
|
||||
if (call == NULL) {
|
||||
|
@ -1235,7 +1360,9 @@ PyCallable_Check(PyObject *x)
|
|||
Py_DECREF(call);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
else {
|
||||
return x->ob_type->tp_call != NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1365,7 +1492,7 @@ _Py_ForgetReference(register PyObject *op)
|
|||
op->_ob_prev->_ob_next = op->_ob_next;
|
||||
op->_ob_next = op->_ob_prev = NULL;
|
||||
#ifdef COUNT_ALLOCS
|
||||
op->ob_type->tp_free++;
|
||||
op->ob_type->tp_frees++;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -310,22 +310,34 @@ PyTypeObject PyRange_Type = {
|
|||
"xrange", /* Name of this type */
|
||||
sizeof(rangeobject), /* Basic object size */
|
||||
0, /* Item size for varobject */
|
||||
(destructor)range_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)range_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
(cmpfunc)range_compare, /*tp_compare*/
|
||||
(reprfunc)range_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&range_as_sequence, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
(destructor)range_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)range_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
(cmpfunc)range_compare, /*tp_compare*/
|
||||
(reprfunc)range_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&range_as_sequence, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
PyObject_GenericGetAttr, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
};
|
||||
|
||||
#undef WARN
|
||||
|
|
|
@ -14,6 +14,7 @@ this type and there is exactly one in existence.
|
|||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
static PyObject *
|
||||
ellipsis_repr(PyObject *op)
|
||||
|
@ -128,32 +129,12 @@ slice_repr(PySliceObject *r)
|
|||
return s;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *slice_getattr(PySliceObject *self, char *name)
|
||||
{
|
||||
PyObject *ret;
|
||||
|
||||
ret = NULL;
|
||||
if (strcmp(name, "start") == 0) {
|
||||
ret = self->start;
|
||||
}
|
||||
else if (strcmp(name, "stop") == 0) {
|
||||
ret = self->stop;
|
||||
}
|
||||
else if (strcmp(name, "step") == 0) {
|
||||
ret = self->step;
|
||||
}
|
||||
else if (strcmp(name, "__members__") == 0) {
|
||||
return Py_BuildValue("[sss]",
|
||||
"start", "stop", "step");
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_AttributeError, name);
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(ret);
|
||||
return ret;
|
||||
}
|
||||
static struct memberlist slice_members[] = {
|
||||
{"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
|
||||
{"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
|
||||
{"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
|
||||
{0}
|
||||
};
|
||||
|
||||
static int
|
||||
slice_compare(PySliceObject *v, PySliceObject *w)
|
||||
|
@ -182,13 +163,32 @@ PyTypeObject PySlice_Type = {
|
|||
"slice", /* Name of this type */
|
||||
sizeof(PySliceObject), /* Basic object size */
|
||||
0, /* Item size for varobject */
|
||||
(destructor)slice_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
(getattrfunc)slice_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
(cmpfunc)slice_compare, /*tp_compare*/
|
||||
(reprfunc)slice_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
(destructor)slice_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
(cmpfunc)slice_compare, /* tp_compare */
|
||||
(reprfunc)slice_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
slice_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
};
|
||||
|
|
|
@ -2522,41 +2522,65 @@ string_methods[] = {
|
|||
};
|
||||
|
||||
static PyObject *
|
||||
string_getattr(PyStringObject *s, char *name)
|
||||
string_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
return Py_FindMethod(string_methods, (PyObject*)s, name);
|
||||
PyObject *x = NULL;
|
||||
static char *kwlist[] = {"object", 0};
|
||||
|
||||
assert(type == &PyString_Type);
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:str", kwlist, &x))
|
||||
return NULL;
|
||||
if (x == NULL)
|
||||
return PyString_FromString("");
|
||||
return PyObject_Str(x);
|
||||
}
|
||||
|
||||
static char string_doc[] =
|
||||
"str(object) -> string\n\
|
||||
\n\
|
||||
Return a nice string representation of the object.\n\
|
||||
If the argument is a string, the return value is the same object.";
|
||||
|
||||
PyTypeObject PyString_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"string",
|
||||
"str",
|
||||
sizeof(PyStringObject),
|
||||
sizeof(char),
|
||||
(destructor)string_dealloc, /*tp_dealloc*/
|
||||
(printfunc)string_print, /*tp_print*/
|
||||
(getattrfunc)string_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
(reprfunc)string_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
&string_as_sequence, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
(hashfunc)string_hash, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
(reprfunc)string_str, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
&string_as_buffer, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||
0, /*tp_doc*/
|
||||
0, /*tp_traverse*/
|
||||
0, /*tp_clear*/
|
||||
(richcmpfunc)string_richcompare, /*tp_richcompare*/
|
||||
0, /*tp_weaklistoffset*/
|
||||
0, /*tp_iter*/
|
||||
0, /*tp_iternext*/
|
||||
(destructor)string_dealloc, /* tp_dealloc */
|
||||
(printfunc)string_print, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
(reprfunc)string_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
&string_as_sequence, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)string_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
(reprfunc)string_str, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&string_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
string_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
(richcmpfunc)string_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
string_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
string_new, /* tp_new */
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -480,6 +480,28 @@ tuplerichcompare(PyObject *v, PyObject *w, int op)
|
|||
return PyObject_RichCompare(vt->ob_item[i], wt->ob_item[i], op);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *arg = NULL;
|
||||
static char *kwlist[] = {"sequence", 0};
|
||||
|
||||
assert(type == &PyTuple_Type);
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:tuple", kwlist, &arg))
|
||||
return NULL;
|
||||
|
||||
if (arg == NULL)
|
||||
return PyTuple_New(0);
|
||||
else
|
||||
return PySequence_Tuple(arg);
|
||||
}
|
||||
|
||||
static char tuple_doc[] =
|
||||
"tuple(sequence) -> list\n\
|
||||
\n\
|
||||
Return a tuple whose items are the same as those of the argument sequence.\n\
|
||||
If the argument is a tuple, the return value is the same object.";
|
||||
|
||||
static PySequenceMethods tuple_as_sequence = {
|
||||
(inquiry)tuplelength, /* sq_length */
|
||||
(binaryfunc)tupleconcat, /* sq_concat */
|
||||
|
@ -509,14 +531,28 @@ PyTypeObject PyTuple_Type = {
|
|||
(hashfunc)tuplehash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
tuple_doc, /* tp_doc */
|
||||
(traverseproc)tupletraverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
tuplerichcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
tuple_new, /* tp_new */
|
||||
};
|
||||
|
||||
/* The following function breaks the notion that tuples are immutable:
|
||||
|
|
2358
Objects/typeobject.c
2358
Objects/typeobject.c
File diff suppressed because it is too large
Load diff
|
@ -4667,12 +4667,6 @@ static PyMethodDef unicode_methods[] = {
|
|||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
unicode_getattr(PyUnicodeObject *self, char *name)
|
||||
{
|
||||
return Py_FindMethod(unicode_methods, (PyObject*) self, name);
|
||||
}
|
||||
|
||||
static PySequenceMethods unicode_as_sequence = {
|
||||
(inquiry) unicode_length, /* sq_length */
|
||||
(binaryfunc) PyUnicode_Concat, /* sq_concat */
|
||||
|
@ -5346,6 +5340,30 @@ static PyBufferProcs unicode_as_buffer = {
|
|||
(getcharbufferproc) unicode_buffer_getcharbuf,
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *x = NULL;
|
||||
static char *kwlist[] = {"string", "encoding", "errors", 0};
|
||||
char *encoding = NULL;
|
||||
char *errors = NULL;
|
||||
|
||||
assert(type == &PyUnicode_Type);
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:unicode",
|
||||
kwlist, &x, &encoding, &errors))
|
||||
return NULL;
|
||||
if (x == NULL)
|
||||
return (PyObject *)_PyUnicode_New(0);
|
||||
return PyUnicode_FromEncodedObject(x, encoding, errors);
|
||||
}
|
||||
|
||||
static char unicode_doc[] =
|
||||
"unicode(string [, encoding[, errors]]) -> object\n\
|
||||
\n\
|
||||
Create a new Unicode object from the given encoded string.\n\
|
||||
encoding defaults to the current default string encoding and \n\
|
||||
errors, defining the error handling, to 'strict'.";
|
||||
|
||||
PyTypeObject PyUnicode_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /* ob_size */
|
||||
|
@ -5355,7 +5373,7 @@ PyTypeObject PyUnicode_Type = {
|
|||
/* Slots */
|
||||
(destructor)_PyUnicode_Free, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
(getattrfunc)unicode_getattr, /* tp_getattr */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
(cmpfunc) unicode_compare, /* tp_compare */
|
||||
(reprfunc) unicode_repr, /* tp_repr */
|
||||
|
@ -5365,10 +5383,28 @@ PyTypeObject PyUnicode_Type = {
|
|||
(hashfunc) unicode_hash, /* tp_hash*/
|
||||
0, /* tp_call*/
|
||||
(reprfunc) unicode_str, /* tp_str */
|
||||
(getattrofunc) NULL, /* tp_getattro */
|
||||
(setattrofunc) NULL, /* tp_setattro */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&unicode_as_buffer, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
unicode_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
unicode_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
unicode_new, /* tp_new */
|
||||
};
|
||||
|
||||
/* Initialize the Unicode implementation */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue