summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-08-02 04:15:00 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-08-02 04:15:00 (GMT)
commit6d6c1a35e08b95a83dbe47dbd9e6474daff00354 (patch)
tree542089077b9c2650dcf5c52d6bfcef1baf12d176 /Objects
parent52d55a392600011d3edfe85c694744ec550ad1fe (diff)
downloadcpython-6d6c1a35e08b95a83dbe47dbd9e6474daff00354.zip
cpython-6d6c1a35e08b95a83dbe47dbd9e6474daff00354.tar.gz
cpython-6d6c1a35e08b95a83dbe47dbd9e6474daff00354.tar.bz2
Merge of descr-branch back into trunk.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/abstract.c20
-rw-r--r--Objects/bufferobject.c34
-rw-r--r--Objects/cellobject.c2
-rw-r--r--Objects/classobject.c235
-rw-r--r--Objects/complexobject.c303
-rw-r--r--Objects/descrobject.c854
-rw-r--r--Objects/dictobject.c230
-rw-r--r--Objects/fileobject.c45
-rw-r--r--Objects/floatobject.c70
-rw-r--r--Objects/frameobject.c35
-rw-r--r--Objects/funcobject.c380
-rw-r--r--Objects/intobject.c85
-rw-r--r--Objects/iterobject.c34
-rw-r--r--Objects/listobject.c158
-rw-r--r--Objects/longobject.c95
-rw-r--r--Objects/methodobject.c117
-rw-r--r--Objects/moduleobject.c101
-rw-r--r--Objects/object.c293
-rw-r--r--Objects/rangeobject.c44
-rw-r--r--Objects/sliceobject.c70
-rw-r--r--Objects/stringobject.c76
-rw-r--r--Objects/tupleobject.c40
-rw-r--r--Objects/typeobject.c2358
-rw-r--r--Objects/unicodeobject.c54
24 files changed, 5012 insertions, 721 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 63fe7d5..a0f075f 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1589,6 +1589,24 @@ PyObject_CallObject(PyObject *o, PyObject *a)
}
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, ...)
{
va_list va;
@@ -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) {
diff --git a/Objects/bufferobject.c b/Objects/bufferobject.c
index 1a17ec5..4c213ce 100644
--- a/Objects/bufferobject.c
+++ b/Objects/bufferobject.c
@@ -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 */
};
diff --git a/Objects/cellobject.c b/Objects/cellobject.c
index 66fc8d1..9a36776 100644
--- a/Objects/cellobject.c
+++ b/Objects/cellobject.c
@@ -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 */
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 06f6714..c4b1d8e 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -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);
- }
- else {
- funcname = PyObject_GetAttrString(func,"__name__");
- if (funcname == NULL)
- PyErr_Clear();
+ 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;
}
- if (funcname != NULL && PyString_Check(funcname))
- fname = PyString_AS_STRING(funcname);
else
- fname = "?";
- if (fclassname != NULL && PyString_Check(fclassname))
- fcname = PyString_AsString(fclassname);
+ 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;
+ }
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 */
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index 34dbab0..9a66c0c 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -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)
-{
- 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);
+complex_subtype_from_string(PyTypeObject *type, PyObject *v)
+{
+ 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
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
new file mode 100644
index 0000000..40629f6
--- /dev/null
+++ b/Objects/descrobject.c
@@ -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;
+}
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index c17664e..ce4c578 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -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", &param))
- 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)
{
@@ -1732,6 +1683,26 @@ static PySequenceMethods dict_as_sequence = {
};
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)
{
return dictiter_new(dict, select_key);
@@ -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 */
};
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 18d15e1..e192e8b 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -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. */
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index d1ce092..df88736 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -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
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 0801b93..d327616 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -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 *
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 09c6cb8..311bcde 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -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;
+}
diff --git a/Objects/intobject.c b/Objects/intobject.c
index 282da20..e5106c5 100644
--- a/Objects/intobject.c
+++ b/Objects/intobject.c
@@ -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
diff --git a/Objects/iterobject.c b/Objects/iterobject.c
index c4f4e61..e062c8a 100644
--- a/Objects/iterobject.c
+++ b/Objects/iterobject.c
@@ -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 */
};
/* -------------------------------------- */
@@ -198,12 +199,6 @@ static PyMethodDef calliter_methods[] = {
};
static PyObject *
-calliter_getattr(calliterobject *it, char *name)
-{
- return Py_FindMethod(calliter_methods, (PyObject *)it, name);
-}
-
-static PyObject *
calliter_iternext(calliterobject *it)
{
PyObject *result = PyObject_CallObject(it->it_callable, NULL);
@@ -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 */
};
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 7166ced..b77cc0a 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -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! */
};
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 71bd1ce..28c3e57 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -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 */
};
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index bff79ed..56fbcc2 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -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);
- }
- 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__");
+ PyObject *self;
+ if (PyEval_GetRestricted()) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "method.__self__ not accessible in restricted mode");
+ return NULL;
}
- 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 */
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index 7df5ce0..7faa3bb 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -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 */
};
diff --git a/Objects/object.c b/Objects/object.c
index 87c8e1a..137752d 100644
--- a/Objects/object.c
+++ b/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
}
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c
index 1f446df..9f155cf 100644
--- a/Objects/rangeobject.c
+++ b/Objects/rangeobject.c
@@ -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
diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c
index 6f7a6d8..8f52f9e 100644
--- a/Objects/sliceobject.c
+++ b/Objects/sliceobject.c
@@ -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 */
};
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index c7f5062..3d12588 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -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
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 538cc70..46f5714 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -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:
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index ea3494e..429680d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2,27 +2,78 @@
/* Type object implementation */
#include "Python.h"
+#include "structmember.h"
-/* Type object implementation */
+staticforward int add_members(PyTypeObject *, struct memberlist *);
+
+static struct memberlist type_members[] = {
+ {"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
+ {"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
+ {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY},
+ {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY},
+ {"__doc__", T_STRING, offsetof(PyTypeObject, tp_doc), READONLY},
+ {"__weaklistoffset__", T_LONG,
+ offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
+ {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
+ {"__dictoffset__", T_LONG,
+ offsetof(PyTypeObject, tp_dictoffset), READONLY},
+ {"__bases__", T_OBJECT, offsetof(PyTypeObject, tp_bases), READONLY},
+ {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
+ {0}
+};
+
+static PyObject *
+type_module(PyTypeObject *type, void *context)
+{
+ return PyString_FromString("__builtin__");
+}
static PyObject *
-type_getattr(PyTypeObject *t, char *name)
+type_dict(PyTypeObject *type, void *context)
{
- if (strcmp(name, "__name__") == 0)
- return PyString_FromString(t->tp_name);
- if (strcmp(name, "__doc__") == 0) {
- char *doc = t->tp_doc;
- if (doc != NULL)
- return PyString_FromString(doc);
+ if (type->tp_dict == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
- if (strcmp(name, "__members__") == 0)
- return Py_BuildValue("[ss]", "__doc__", "__name__");
- PyErr_SetString(PyExc_AttributeError, name);
- return NULL;
+ if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+ Py_INCREF(type->tp_dict);
+ return type->tp_dict;
+ }
+ return PyDictProxy_New(type->tp_dict);
}
+static PyObject *
+type_defined(PyTypeObject *type, void *context)
+{
+ if (type->tp_defined == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+ Py_INCREF(type->tp_defined);
+ return type->tp_defined;
+ }
+ return PyDictProxy_New(type->tp_defined);
+}
+
+static PyObject *
+type_dynamic(PyTypeObject *type, void *context)
+{
+ PyObject *res;
+
+ res = (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) ? Py_True : Py_False;
+ Py_INCREF(res);
+ return res;
+}
+
+struct getsetlist type_getsets[] = {
+ {"__module__", (getter)type_module, NULL, NULL},
+ {"__dict__", (getter)type_dict, NULL, NULL},
+ {"__defined__", (getter)type_defined, NULL, NULL},
+ {"__dynamic__", (getter)type_dynamic, NULL, NULL},
+ {0}
+};
+
static int
type_compare(PyObject *v, PyObject *w)
{
@@ -34,34 +85,2271 @@ type_compare(PyObject *v, PyObject *w)
}
static PyObject *
-type_repr(PyTypeObject *v)
+type_repr(PyTypeObject *type)
{
char buf[100];
- sprintf(buf, "<type '%.80s'>", v->tp_name);
+ sprintf(buf, "<type '%.80s'>", type->tp_name);
return PyString_FromString(buf);
}
+static PyObject *
+type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if (type->tp_new == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "cannot create '%.100s' instances",
+ type->tp_name);
+ return NULL;
+ }
+
+ obj = type->tp_new(type, args, NULL);
+ if (obj != NULL) {
+ type = obj->ob_type;
+ if (type->tp_init != NULL &&
+ type->tp_init(obj, args, kwds) < 0) {
+ Py_DECREF(obj);
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
+PyObject *
+PyType_GenericAlloc(PyTypeObject *type, int nitems)
+{
+ int size;
+ void *mem;
+ PyObject *obj;
+
+ /* Inline PyObject_New() so we can zero the memory */
+ size = _PyObject_VAR_SIZE(type, nitems);
+ mem = PyObject_MALLOC(size);
+ if (mem == NULL)
+ return PyErr_NoMemory();
+ memset(mem, '\0', size);
+ if (PyType_IS_GC(type))
+ obj = PyObject_FROM_GC(mem);
+ else
+ obj = (PyObject *)mem;
+ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ Py_INCREF(type);
+ if (type->tp_itemsize == 0)
+ PyObject_INIT(obj, type);
+ else
+ (void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
+ if (PyType_IS_GC(type))
+ PyObject_GC_Init(obj);
+ return obj;
+}
+
+PyObject *
+PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ return type->tp_alloc(type, 0);
+}
+
+/* Helper for subtyping */
+
+static void
+subtype_dealloc(PyObject *self)
+{
+ int dictoffset = self->ob_type->tp_dictoffset;
+ PyTypeObject *type, *base;
+ destructor f;
+
+ /* This exists so we can DECREF self->ob_type */
+
+ /* Find the nearest base with a different tp_dealloc */
+ type = self->ob_type;
+ base = type->tp_base;
+ while ((f = base->tp_dealloc) == subtype_dealloc) {
+ base = base->tp_base;
+ assert(base);
+ }
+
+ /* If we added a dict, DECREF it */
+ if (dictoffset && !base->tp_dictoffset) {
+ PyObject **dictptr = (PyObject **) ((char *)self + dictoffset);
+ PyObject *dict = *dictptr;
+ if (dict != NULL) {
+ Py_DECREF(dict);
+ *dictptr = NULL;
+ }
+ }
+
+ /* Finalize GC if the base doesn't do GC and we do */
+ if (PyType_IS_GC(type) && !PyType_IS_GC(base))
+ PyObject_GC_Fini(self);
+
+ /* Call the base tp_dealloc() */
+ assert(f);
+ f(self);
+
+ /* Can't reference self beyond this point */
+ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+ Py_DECREF(type);
+ }
+}
+
+staticforward void override_slots(PyTypeObject *type, PyObject *dict);
+staticforward PyTypeObject *solid_base(PyTypeObject *type);
+
+typedef struct {
+ PyTypeObject type;
+ PyNumberMethods as_number;
+ PySequenceMethods as_sequence;
+ PyMappingMethods as_mapping;
+ PyBufferProcs as_buffer;
+ PyObject *name, *slots;
+ struct memberlist members[1];
+} etype;
+
+/* type test with subclassing support */
+
+int
+PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
+{
+ PyObject *mro;
+
+ mro = a->tp_mro;
+ if (mro != NULL) {
+ /* Deal with multiple inheritance without recursion
+ by walking the MRO tuple */
+ int i, n;
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b)
+ return 1;
+ }
+ return 0;
+ }
+ else {
+ /* a is not completely initilized yet; follow tp_base */
+ do {
+ if (a == b)
+ return 1;
+ a = a->tp_base;
+ } while (a != NULL);
+ return b == &PyBaseObject_Type;
+ }
+}
+
+/* Method resolution order algorithm from "Putting Metaclasses to Work"
+ by Forman and Danforth (Addison-Wesley 1999). */
+
+static int
+conservative_merge(PyObject *left, PyObject *right)
+{
+ int left_size;
+ int right_size;
+ int i, j, r, ok;
+ PyObject *temp, *rr;
+
+ assert(PyList_Check(left));
+ assert(PyList_Check(right));
+
+ again:
+ left_size = PyList_GET_SIZE(left);
+ right_size = PyList_GET_SIZE(right);
+ for (i = 0; i < left_size; i++) {
+ for (j = 0; j < right_size; j++) {
+ if (PyList_GET_ITEM(left, i) ==
+ PyList_GET_ITEM(right, j)) {
+ /* found a merge point */
+ temp = PyList_New(0);
+ if (temp == NULL)
+ return -1;
+ for (r = 0; r < j; r++) {
+ rr = PyList_GET_ITEM(right, r);
+ ok = PySequence_Contains(left, rr);
+ if (ok < 0) {
+ Py_DECREF(temp);
+ return -1;
+ }
+ if (!ok) {
+ ok = PyList_Append(temp, rr);
+ if (ok < 0) {
+ Py_DECREF(temp);
+ return -1;
+ }
+ }
+ }
+ ok = PyList_SetSlice(left, i, i, temp);
+ Py_DECREF(temp);
+ if (ok < 0)
+ return -1;
+ ok = PyList_SetSlice(right, 0, j+1, NULL);
+ if (ok < 0)
+ return -1;
+ goto again;
+ }
+ }
+ }
+ return PyList_SetSlice(left, left_size, left_size, right);
+}
+
+static int
+serious_order_disagreements(PyObject *left, PyObject *right)
+{
+ return 0; /* XXX later -- for now, we cheat: "don't do that" */
+}
+
+static PyObject *
+mro_implementation(PyTypeObject *type)
+{
+ int i, n, ok;
+ PyObject *bases, *result;
+
+ bases = type->tp_bases;
+ n = PyTuple_GET_SIZE(bases);
+ result = Py_BuildValue("[O]", (PyObject *)type);
+ if (result == NULL)
+ return NULL;
+ for (i = 0; i < n; i++) {
+ PyTypeObject *base =
+ (PyTypeObject *) PyTuple_GET_ITEM(bases, i);
+ PyObject *parentMRO = PySequence_List(base->tp_mro);
+ if (parentMRO == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ if (serious_order_disagreements(result, parentMRO)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ ok = conservative_merge(result, parentMRO);
+ Py_DECREF(parentMRO);
+ if (ok < 0) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ }
+ return result;
+}
+
+static PyObject *
+mro_external(PyObject *self, PyObject *args)
+{
+ PyTypeObject *type = (PyTypeObject *)self;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+ return mro_implementation(type);
+}
+
+static int
+mro_internal(PyTypeObject *type)
+{
+ PyObject *mro, *result, *tuple;
+
+ if (type->ob_type == &PyType_Type) {
+ result = mro_implementation(type);
+ }
+ else {
+ mro = PyObject_GetAttrString((PyObject *)type, "mro");
+ if (mro == NULL)
+ return -1;
+ result = PyObject_CallObject(mro, NULL);
+ Py_DECREF(mro);
+ }
+ if (result == NULL)
+ return -1;
+ tuple = PySequence_Tuple(result);
+ Py_DECREF(result);
+ type->tp_mro = tuple;
+ return 0;
+}
+
+
+/* Calculate the best base amongst multiple base classes.
+ This is the first one that's on the path to the "solid base". */
+
+static PyTypeObject *
+best_base(PyObject *bases)
+{
+ int i, n;
+ PyTypeObject *base, *winner, *candidate, *base_i;
+
+ assert(PyTuple_Check(bases));
+ n = PyTuple_GET_SIZE(bases);
+ assert(n > 0);
+ base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
+ winner = &PyBaseObject_Type;
+ for (i = 0; i < n; i++) {
+ base_i = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+ if (!PyType_Check((PyObject *)base_i)) {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "bases must be types");
+ return NULL;
+ }
+ if (base_i->tp_dict == NULL) {
+ if (PyType_InitDict(base_i) < 0)
+ return NULL;
+ }
+ candidate = solid_base(base_i);
+ if (PyType_IsSubtype(winner, candidate))
+ ;
+ else if (PyType_IsSubtype(candidate, winner)) {
+ winner = candidate;
+ base = base_i;
+ }
+ else {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "multiple bases have "
+ "instance lay-out conflict");
+ return NULL;
+ }
+ }
+ assert(base != NULL);
+ return base;
+}
+
+static int
+extra_ivars(PyTypeObject *type, PyTypeObject *base)
+{
+ int t_size = PyType_BASICSIZE(type);
+ int b_size = PyType_BASICSIZE(base);
+
+ assert(t_size >= b_size); /* type smaller than base! */
+ if (type->tp_itemsize || base->tp_itemsize) {
+ /* If itemsize is involved, stricter rules */
+ return t_size != b_size ||
+ type->tp_itemsize != base->tp_itemsize;
+ }
+ if (t_size == b_size)
+ return 0;
+ if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 &&
+ type->tp_dictoffset == b_size &&
+ (size_t)t_size == b_size + sizeof(PyObject *))
+ return 0; /* "Forgive" adding a __dict__ only */
+ return 1;
+}
+
+static PyTypeObject *
+solid_base(PyTypeObject *type)
+{
+ PyTypeObject *base;
+
+ if (type->tp_base)
+ base = solid_base(type->tp_base);
+ else
+ base = &PyBaseObject_Type;
+ if (extra_ivars(type, base))
+ return type;
+ else
+ return base;
+}
+
+staticforward void object_dealloc(PyObject *);
+staticforward int object_init(PyObject *, PyObject *, PyObject *);
+
+static PyObject *
+type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
+{
+ PyObject *name, *bases, *dict;
+ static char *kwlist[] = {"name", "bases", "dict", 0};
+ PyObject *slots, *tmp;
+ PyTypeObject *type, *base, *tmptype;
+ etype *et;
+ struct memberlist *mp;
+ int i, nbases, nslots, slotoffset, dynamic;
+
+ if (metatype == &PyType_Type &&
+ PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
+ (kwds == NULL || (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) {
+ /* type(x) -> x.__class__ */
+ PyObject *x = PyTuple_GET_ITEM(args, 0);
+ Py_INCREF(x->ob_type);
+ return (PyObject *) x->ob_type;
+ }
+
+ /* Check arguments */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:type", kwlist,
+ &name,
+ &PyTuple_Type, &bases,
+ &PyDict_Type, &dict))
+ return NULL;
+
+ /* Determine the proper metatype to deal with this,
+ and check for metatype conflicts while we're at it.
+ Note that if some other metatype wins to contract,
+ it's possible that its instances are not types. */
+ nbases = PyTuple_GET_SIZE(bases);
+ for (i = 0; i < nbases; i++) {
+ tmp = PyTuple_GET_ITEM(bases, i);
+ tmptype = tmp->ob_type;
+ if (PyType_IsSubtype(metatype, tmptype))
+ continue;
+ if (PyType_IsSubtype(tmptype, metatype)) {
+ metatype = tmptype;
+ continue;
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "metatype conflict among bases");
+ return NULL;
+ }
+ if (metatype->tp_new != type_new) /* Pass it to the winner */
+ return metatype->tp_new(metatype, args, kwds);
+
+ /* Adjust for empty tuple bases */
+ if (nbases == 0) {
+ bases = Py_BuildValue("(O)", &PyBaseObject_Type);
+ if (bases == NULL)
+ return NULL;
+ nbases = 1;
+ }
+ else
+ Py_INCREF(bases);
+
+ /* XXX From here until type is allocated, "return NULL" leaks bases! */
+
+ /* Calculate best base, and check that all bases are type objects */
+ base = best_base(bases);
+ if (base == NULL)
+ return NULL;
+ if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) {
+ PyErr_Format(PyExc_TypeError,
+ "type '%.100s' is not an acceptable base type",
+ base->tp_name);
+ return NULL;
+ }
+
+ /* Should this be a dynamic class (i.e. modifiable __dict__)? */
+ tmp = PyDict_GetItemString(dict, "__dynamic__");
+ if (tmp != NULL) {
+ /* The class author has a preference */
+ dynamic = PyObject_IsTrue(tmp);
+ Py_DECREF(tmp);
+ if (dynamic < 0)
+ return NULL;
+ }
+ else {
+ /* Make a new class dynamic if any of its bases is dynamic.
+ This is not always the same as inheriting the __dynamic__
+ class attribute! */
+ dynamic = 0;
+ for (i = 0; i < nbases; i++) {
+ tmptype = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+ if (tmptype->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+ dynamic = 1;
+ break;
+ }
+ }
+ }
+
+ /* Check for a __slots__ sequence variable in dict, and count it */
+ slots = PyDict_GetItemString(dict, "__slots__");
+ nslots = 0;
+ if (slots != NULL) {
+ /* Make it into a tuple */
+ if (PyString_Check(slots))
+ slots = Py_BuildValue("(O)", slots);
+ else
+ slots = PySequence_Tuple(slots);
+ if (slots == NULL)
+ return NULL;
+ nslots = PyTuple_GET_SIZE(slots);
+ for (i = 0; i < nslots; i++) {
+ if (!PyString_Check(PyTuple_GET_ITEM(slots, i))) {
+ PyErr_SetString(PyExc_TypeError,
+ "__slots__ must be a sequence of strings");
+ Py_DECREF(slots);
+ return NULL;
+ }
+ }
+ }
+ if (slots == NULL && base->tp_dictoffset == 0 &&
+ (base->tp_setattro == PyObject_GenericSetAttr ||
+ base->tp_setattro == NULL))
+ nslots = 1;
+
+ /* XXX From here until type is safely allocated,
+ "return NULL" may leak slots! */
+
+ /* Allocate the type object */
+ type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots);
+ if (type == NULL)
+ return NULL;
+
+ /* Keep name and slots alive in the extended type object */
+ et = (etype *)type;
+ Py_INCREF(name);
+ et->name = name;
+ et->slots = slots;
+
+ /* Initialize essential fields */
+ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
+ Py_TPFLAGS_BASETYPE;
+ if (dynamic)
+ type->tp_flags |= Py_TPFLAGS_DYNAMICTYPE;
+ type->tp_as_number = &et->as_number;
+ type->tp_as_sequence = &et->as_sequence;
+ type->tp_as_mapping = &et->as_mapping;
+ type->tp_as_buffer = &et->as_buffer;
+ type->tp_name = PyString_AS_STRING(name);
+
+ /* Set tp_base and tp_bases */
+ type->tp_bases = bases;
+ Py_INCREF(base);
+ type->tp_base = base;
+
+ /* Initialize tp_defined from passed-in dict */
+ type->tp_defined = dict = PyDict_Copy(dict);
+ if (dict == NULL) {
+ Py_DECREF(type);
+ return NULL;
+ }
+
+ /* Special-case __new__: if it's a plain function,
+ make it a static function */
+ tmp = PyDict_GetItemString(dict, "__new__");
+ if (tmp != NULL && PyFunction_Check(tmp)) {
+ tmp = PyStaticMethod_New(tmp);
+ if (tmp == NULL) {
+ Py_DECREF(type);
+ return NULL;
+ }
+ PyDict_SetItemString(dict, "__new__", tmp);
+ Py_DECREF(tmp);
+ }
+
+ /* Add descriptors for custom slots from __slots__, or for __dict__ */
+ mp = et->members;
+ slotoffset = PyType_BASICSIZE(base);
+ if (slots != NULL) {
+ for (i = 0; i < nslots; i++, mp++) {
+ mp->name = PyString_AS_STRING(
+ PyTuple_GET_ITEM(slots, i));
+ mp->type = T_OBJECT;
+ mp->offset = slotoffset;
+ slotoffset += sizeof(PyObject *);
+ }
+ }
+ else if (nslots) {
+ type->tp_dictoffset = slotoffset;
+ mp->name = "__dict__";
+ mp->type = T_OBJECT;
+ mp->offset = slotoffset;
+ mp->readonly = 1;
+ slotoffset += sizeof(PyObject *);
+ }
+ type->tp_basicsize = slotoffset;
+ add_members(type, et->members);
+
+ /* Special case some slots */
+ if (type->tp_dictoffset != 0 || nslots > 0) {
+ if (base->tp_getattr == NULL && base->tp_getattro == NULL)
+ type->tp_getattro = PyObject_GenericGetAttr;
+ if (base->tp_setattr == NULL && base->tp_setattro == NULL)
+ type->tp_setattro = PyObject_GenericSetAttr;
+ }
+ type->tp_dealloc = subtype_dealloc;
+
+ /* Always override allocation strategy to use regular heap */
+ type->tp_alloc = PyType_GenericAlloc;
+ type->tp_free = _PyObject_Del;
+
+ /* Initialize the rest */
+ if (PyType_InitDict(type) < 0) {
+ Py_DECREF(type);
+ return NULL;
+ }
+
+ /* Override slots that deserve it */
+ override_slots(type, type->tp_defined);
+ return (PyObject *)type;
+}
+
+/* Internal API to look for a name through the MRO.
+ This returns a borrowed reference, and doesn't set an exception! */
+PyObject *
+_PyType_Lookup(PyTypeObject *type, PyObject *name)
+{
+ int i, n;
+ PyObject *mro, *res, *dict;
+
+ /* For static types, look in tp_dict */
+ if (!(type->tp_flags & Py_TPFLAGS_DYNAMICTYPE)) {
+ dict = type->tp_dict;
+ assert(dict && PyDict_Check(dict));
+ return PyDict_GetItem(dict, name);
+ }
+
+ /* For dynamic types, look in tp_defined of types in MRO */
+ mro = type->tp_mro;
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ type = (PyTypeObject *) PyTuple_GET_ITEM(mro, i);
+ assert(PyType_Check(type));
+ dict = type->tp_defined;
+ assert(dict && PyDict_Check(dict));
+ res = PyDict_GetItem(dict, name);
+ if (res != NULL)
+ return res;
+ }
+ return NULL;
+}
+
+/* This is similar to PyObject_GenericGetAttr(),
+ but uses _PyType_Lookup() instead of just looking in type->tp_dict. */
+static PyObject *
+type_getattro(PyTypeObject *type, PyObject *name)
+{
+ PyTypeObject *metatype = type->ob_type;
+ PyObject *descr, *res;
+ descrgetfunc f;
+
+ /* Initialize this type (we'll assume the metatype is initialized) */
+ if (type->tp_dict == NULL) {
+ if (PyType_InitDict(type) < 0)
+ return NULL;
+ }
+
+ /* Get a descriptor from the metatype */
+ descr = _PyType_Lookup(metatype, name);
+ f = NULL;
+ if (descr != NULL) {
+ f = descr->ob_type->tp_descr_get;
+ if (f != NULL && PyDescr_IsData(descr))
+ return f(descr,
+ (PyObject *)type, (PyObject *)metatype);
+ }
+
+ /* Look in tp_defined of this type and its bases */
+ res = _PyType_Lookup(type, name);
+ if (res != NULL) {
+ f = res->ob_type->tp_descr_get;
+ if (f != NULL)
+ return f(res, (PyObject *)NULL, (PyObject *)type);
+ Py_INCREF(res);
+ return res;
+ }
+
+ /* Use the descriptor from the metatype */
+ if (f != NULL) {
+ res = f(descr, (PyObject *)type, (PyObject *)metatype);
+ return res;
+ }
+ if (descr != NULL) {
+ Py_INCREF(descr);
+ return descr;
+ }
+
+ /* Give up */
+ PyErr_Format(PyExc_AttributeError,
+ "type object '%.50s' has no attribute '%.400s'",
+ type->tp_name, PyString_AS_STRING(name));
+ return NULL;
+}
+
+static int
+type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
+{
+ if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE)
+ return PyObject_GenericSetAttr((PyObject *)type, name, value);
+ PyErr_SetString(PyExc_TypeError, "can't set type attributes");
+ return -1;
+}
+
+static void
+type_dealloc(PyTypeObject *type)
+{
+ etype *et;
+
+ /* Assert this is a heap-allocated type object */
+ assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
+ et = (etype *)type;
+ Py_XDECREF(type->tp_base);
+ Py_XDECREF(type->tp_dict);
+ Py_XDECREF(type->tp_bases);
+ Py_XDECREF(type->tp_mro);
+ Py_XDECREF(type->tp_defined);
+ /* XXX more? */
+ Py_XDECREF(et->name);
+ Py_XDECREF(et->slots);
+ type->ob_type->tp_free((PyObject *)type);
+}
+
+static PyMethodDef type_methods[] = {
+ {"mro", mro_external, METH_VARARGS,
+ "mro() -> list\nreturn a type's method resolution order"},
+ {0}
+};
+
+static char type_doc[] =
+"type(object) -> the object's type\n"
+"type(name, bases, dict) -> a new type";
+
PyTypeObject PyType_Type = {
PyObject_HEAD_INIT(&PyType_Type)
- 0, /* Number of items for varobject */
- "type", /* Name of this type */
- sizeof(PyTypeObject), /* Basic object size */
- 0, /* Item size for varobject */
- 0, /*tp_dealloc*/
- 0, /*tp_print*/
- (getattrfunc)type_getattr, /*tp_getattr*/
- 0, /*tp_setattr*/
- type_compare, /*tp_compare*/
- (reprfunc)type_repr, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- (hashfunc)_Py_HashPointer, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_xxx1*/
- 0, /*tp_xxx2*/
- 0, /*tp_xxx3*/
- 0, /*tp_xxx4*/
- "Define the behavior of a particular type of object.",
+ 0, /* ob_size */
+ "type", /* tp_name */
+ sizeof(etype), /* tp_basicsize */
+ sizeof(struct memberlist), /* tp_itemsize */
+ (destructor)type_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ type_compare, /* tp_compare */
+ (reprfunc)type_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)_Py_HashPointer, /* tp_hash */
+ (ternaryfunc)type_call, /* tp_call */
+ 0, /* tp_str */
+ (getattrofunc)type_getattro, /* tp_getattro */
+ (setattrofunc)type_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ type_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ type_methods, /* tp_methods */
+ type_members, /* tp_members */
+ type_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof(PyTypeObject, tp_dict), /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ type_new, /* tp_new */
+};
+
+
+/* The base type of all types (eventually)... except itself. */
+
+static int
+object_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ return 0;
+}
+
+static void
+object_dealloc(PyObject *self)
+{
+ self->ob_type->tp_free(self);
+}
+
+static void
+object_free(PyObject *self)
+{
+ PyObject_Del(self);
+}
+
+static struct memberlist object_members[] = {
+ {"__class__", T_OBJECT, offsetof(PyObject, ob_type), READONLY},
+ {0}
+};
+
+PyTypeObject PyBaseObject_Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /* ob_size */
+ "object", /* tp_name */
+ sizeof(PyObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)object_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 */
+ "The most base type", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ object_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ object_init, /* tp_init */
+ PyType_GenericAlloc, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+ object_free, /* tp_free */
+};
+
+
+/* Initialize the __dict__ in a type object */
+
+static int
+add_methods(PyTypeObject *type, PyMethodDef *meth)
+{
+ PyObject *dict = type->tp_defined;
+
+ for (; meth->ml_name != NULL; meth++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, meth->ml_name))
+ continue;
+ descr = PyDescr_NewMethod(type, meth);
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict,meth->ml_name,descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
+static int
+add_wrappers(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
+{
+ PyObject *dict = type->tp_defined;
+
+ for (; base->name != NULL; base++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, base->name))
+ continue;
+ descr = PyDescr_NewWrapper(type, base, wrapped);
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, base->name, descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
+static int
+add_staticmethodwrappers(PyTypeObject *type, struct wrapperbase *base,
+ void *wrapped)
+{
+ PyObject *dict = type->tp_defined;
+ PyObject *sm;
+
+ for (; base->name != NULL; base++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, base->name))
+ continue;
+ descr = PyDescr_NewWrapper(type->ob_type, base, wrapped);
+ if (descr == NULL)
+ return -1;
+ sm = PyStaticMethod_New(descr);
+ Py_DECREF(descr);
+ if (sm == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, base->name, sm) < 0)
+ return -1;
+ Py_DECREF(sm);
+ }
+ return 0;
+}
+
+static int
+add_members(PyTypeObject *type, struct memberlist *memb)
+{
+ PyObject *dict = type->tp_defined;
+
+ for (; memb->name != NULL; memb++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, memb->name))
+ continue;
+ descr = PyDescr_NewMember(type, memb);
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, memb->name, descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
+static int
+add_getset(PyTypeObject *type, struct getsetlist *gsp)
+{
+ PyObject *dict = type->tp_defined;
+
+ for (; gsp->name != NULL; gsp++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, gsp->name))
+ continue;
+ descr = PyDescr_NewGetSet(type, gsp);
+
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
+staticforward int add_operators(PyTypeObject *);
+
+static int
+inherit_slots(PyTypeObject *type, PyTypeObject *base)
+{
+ int oldsize, newsize;
+
+#undef COPYSLOT
+#undef COPYNUM
+#undef COPYSEQ
+#undef COPYMAP
+#define COPYSLOT(SLOT) \
+ if (!type->SLOT) type->SLOT = base->SLOT
+
+#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT)
+#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT)
+#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT)
+
+ if (type->tp_as_number == NULL)
+ type->tp_as_number = base->tp_as_number;
+ else if (base->tp_as_number) {
+ COPYNUM(nb_add);
+ COPYNUM(nb_subtract);
+ COPYNUM(nb_multiply);
+ COPYNUM(nb_divide);
+ COPYNUM(nb_remainder);
+ COPYNUM(nb_divmod);
+ COPYNUM(nb_power);
+ COPYNUM(nb_negative);
+ COPYNUM(nb_positive);
+ COPYNUM(nb_absolute);
+ COPYNUM(nb_nonzero);
+ COPYNUM(nb_invert);
+ COPYNUM(nb_lshift);
+ COPYNUM(nb_rshift);
+ COPYNUM(nb_and);
+ COPYNUM(nb_xor);
+ COPYNUM(nb_or);
+ COPYNUM(nb_coerce);
+ COPYNUM(nb_int);
+ COPYNUM(nb_long);
+ COPYNUM(nb_float);
+ COPYNUM(nb_oct);
+ COPYNUM(nb_hex);
+ COPYNUM(nb_inplace_add);
+ COPYNUM(nb_inplace_subtract);
+ COPYNUM(nb_inplace_multiply);
+ COPYNUM(nb_inplace_divide);
+ COPYNUM(nb_inplace_remainder);
+ COPYNUM(nb_inplace_power);
+ COPYNUM(nb_inplace_lshift);
+ COPYNUM(nb_inplace_rshift);
+ COPYNUM(nb_inplace_and);
+ COPYNUM(nb_inplace_xor);
+ COPYNUM(nb_inplace_or);
+ }
+
+ if (type->tp_as_sequence == NULL)
+ type->tp_as_sequence = base->tp_as_sequence;
+ else if (base->tp_as_sequence) {
+ COPYSEQ(sq_length);
+ COPYSEQ(sq_concat);
+ COPYSEQ(sq_repeat);
+ COPYSEQ(sq_item);
+ COPYSEQ(sq_slice);
+ COPYSEQ(sq_ass_item);
+ COPYSEQ(sq_ass_slice);
+ COPYSEQ(sq_contains);
+ COPYSEQ(sq_inplace_concat);
+ COPYSEQ(sq_inplace_repeat);
+ }
+
+ if (type->tp_as_mapping == NULL)
+ type->tp_as_mapping = base->tp_as_mapping;
+ else if (base->tp_as_mapping) {
+ COPYMAP(mp_length);
+ COPYMAP(mp_subscript);
+ COPYMAP(mp_ass_subscript);
+ }
+
+ /* Special flag magic */
+ if (!type->tp_as_buffer && base->tp_as_buffer) {
+ type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
+ type->tp_flags |=
+ base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
+ }
+ if (!type->tp_as_sequence && base->tp_as_sequence) {
+ type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
+ type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
+ }
+ if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
+ (base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
+ if ((!type->tp_as_number && base->tp_as_number) ||
+ (!type->tp_as_sequence && base->tp_as_sequence)) {
+ type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
+ if (!type->tp_as_number && !type->tp_as_sequence) {
+ type->tp_flags |= base->tp_flags &
+ Py_TPFLAGS_HAVE_INPLACEOPS;
+ }
+ }
+ /* Wow */
+ }
+ if (!type->tp_as_number && base->tp_as_number) {
+ type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
+ type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
+ }
+
+ /* Copying basicsize is connected to the GC flags */
+ oldsize = PyType_BASICSIZE(base);
+ newsize = type->tp_basicsize ? PyType_BASICSIZE(type) : oldsize;
+ if (!(type->tp_flags & Py_TPFLAGS_GC) &&
+ (base->tp_flags & Py_TPFLAGS_GC) &&
+ (type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
+ (!type->tp_traverse && !type->tp_clear)) {
+ type->tp_flags |= Py_TPFLAGS_GC;
+ COPYSLOT(tp_traverse);
+ COPYSLOT(tp_clear);
+ }
+ PyType_SET_BASICSIZE(type, newsize);
+
+ COPYSLOT(tp_itemsize);
+ COPYSLOT(tp_dealloc);
+ COPYSLOT(tp_print);
+ if (type->tp_getattr == NULL && type->tp_getattro == NULL) {
+ type->tp_getattr = base->tp_getattr;
+ type->tp_getattro = base->tp_getattro;
+ }
+ if (type->tp_setattr == NULL && type->tp_setattro == NULL) {
+ type->tp_setattr = base->tp_setattr;
+ type->tp_setattro = base->tp_setattro;
+ }
+ /* tp_compare see tp_richcompare */
+ COPYSLOT(tp_repr);
+ COPYSLOT(tp_hash);
+ COPYSLOT(tp_call);
+ COPYSLOT(tp_str);
+ COPYSLOT(tp_as_buffer);
+ COPYSLOT(tp_flags);
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
+ if (type->tp_compare == NULL && type->tp_richcompare == NULL) {
+ type->tp_compare = base->tp_compare;
+ type->tp_richcompare = base->tp_richcompare;
+ }
+ }
+ else {
+ COPYSLOT(tp_compare);
+ }
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_WEAKREFS) {
+ COPYSLOT(tp_weaklistoffset);
+ }
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_ITER) {
+ COPYSLOT(tp_iter);
+ COPYSLOT(tp_iternext);
+ }
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
+ COPYSLOT(tp_descr_get);
+ COPYSLOT(tp_descr_set);
+ COPYSLOT(tp_dictoffset);
+ COPYSLOT(tp_init);
+ COPYSLOT(tp_alloc);
+ COPYSLOT(tp_new);
+ COPYSLOT(tp_free);
+ }
+
+ return 0;
+}
+
+int
+PyType_InitDict(PyTypeObject *type)
+{
+ PyObject *dict, *bases, *x;
+ PyTypeObject *base;
+ int i, n;
+
+ if (type->tp_dict != NULL)
+ return 0; /* Already initialized */
+
+ /* Initialize tp_base (defaults to BaseObject unless that's us) */
+ base = type->tp_base;
+ if (base == NULL && type != &PyBaseObject_Type)
+ base = type->tp_base = &PyBaseObject_Type;
+
+ /* Initialize tp_bases */
+ bases = type->tp_bases;
+ if (bases == NULL) {
+ if (base == NULL)
+ bases = PyTuple_New(0);
+ else
+ bases = Py_BuildValue("(O)", base);
+ if (bases == NULL)
+ return -1;
+ type->tp_bases = bases;
+ }
+
+ /* Initialize the base class */
+ if (base) {
+ if (PyType_InitDict(base) < 0)
+ return -1;
+ }
+
+ /* Initialize tp_defined */
+ dict = type->tp_defined;
+ if (dict == NULL) {
+ dict = PyDict_New();
+ if (dict == NULL)
+ return -1;
+ type->tp_defined = dict;
+ }
+
+ /* Add type-specific descriptors to tp_defined */
+ if (add_operators(type) < 0)
+ return -1;
+ if (type->tp_methods != NULL) {
+ if (add_methods(type, type->tp_methods) < 0)
+ return -1;
+ }
+ if (type->tp_members != NULL) {
+ if (add_members(type, type->tp_members) < 0)
+ return -1;
+ }
+ if (type->tp_getset != NULL) {
+ if (add_getset(type, type->tp_getset) < 0)
+ return -1;
+ }
+
+ /* Temporarily make tp_dict the same object as tp_defined.
+ (This is needed to call mro(), and can stay this way for
+ dynamic types). */
+ Py_INCREF(type->tp_defined);
+ type->tp_dict = type->tp_defined;
+
+ /* Calculate method resolution order */
+ if (mro_internal(type) < 0) {
+ return -1;
+ }
+
+ /* Initialize tp_dict properly */
+ if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
+ /* For a static type, tp_dict is the consolidation
+ of the tp_defined of its bases in MRO. Earlier
+ bases override later bases; since d.update() works
+ the other way, we walk the MRO sequence backwards. */
+ Py_DECREF(type->tp_dict);
+ type->tp_dict = PyDict_New();
+ if (type->tp_dict == NULL)
+ return -1;
+ bases = type->tp_mro;
+ assert(bases != NULL);
+ assert(PyTuple_Check(bases));
+ n = PyTuple_GET_SIZE(bases);
+ for (i = n; --i >= 0; ) {
+ base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+ assert(PyType_Check(base));
+ x = base->tp_defined;
+ if (x != NULL && PyDict_Update(type->tp_dict, x) < 0)
+ return -1;
+ }
+ }
+
+ /* Inherit slots from direct base */
+ if (type->tp_base != NULL)
+ if (inherit_slots(type, type->tp_base) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+/* Generic wrappers for overloadable 'operators' such as __getitem__ */
+
+/* There's a wrapper *function* for each distinct function typedef used
+ for type object slots (e.g. binaryfunc, ternaryfunc, etc.). There's a
+ wrapper *table* for each distinct operation (e.g. __len__, __add__).
+ Most tables have only one entry; the tables for binary operators have two
+ entries, one regular and one with reversed arguments. */
+
+static PyObject *
+wrap_inquiry(PyObject *self, PyObject *args, void *wrapped)
+{
+ inquiry func = (inquiry)wrapped;
+ int res;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+ res = (*func)(self);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ return PyInt_FromLong((long)res);
+}
+
+static struct wrapperbase tab_len[] = {
+ {"__len__", (wrapperfunc)wrap_inquiry, "x.__len__() <==> len(x)"},
+ {0}
+};
+
+static PyObject *
+wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ binaryfunc func = (binaryfunc)wrapped;
+ PyObject *other;
+
+ if (!PyArg_ParseTuple(args, "O", &other))
+ return NULL;
+ return (*func)(self, other);
+}
+
+static PyObject *
+wrap_binaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
+{
+ binaryfunc func = (binaryfunc)wrapped;
+ PyObject *other;
+
+ if (!PyArg_ParseTuple(args, "O", &other))
+ return NULL;
+ return (*func)(other, self);
+}
+
+#undef BINARY
+#define BINARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+ {"__" #NAME "__", \
+ (wrapperfunc)wrap_binaryfunc, \
+ "x.__" #NAME "__(y) <==> " #OP}, \
+ {"__r" #NAME "__", \
+ (wrapperfunc)wrap_binaryfunc_r, \
+ "y.__r" #NAME "__(x) <==> " #OP}, \
+ {0} \
+}
+
+BINARY(add, "x+y");
+BINARY(sub, "x-y");
+BINARY(mul, "x*y");
+BINARY(div, "x/y");
+BINARY(mod, "x%y");
+BINARY(divmod, "divmod(x,y)");
+BINARY(lshift, "x<<y");
+BINARY(rshift, "x>>y");
+BINARY(and, "x&y");
+BINARY(xor, "x^y");
+BINARY(or, "x|y");
+
+static PyObject *
+wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ ternaryfunc func = (ternaryfunc)wrapped;
+ PyObject *other;
+ PyObject *third = Py_None;
+
+ /* Note: This wrapper only works for __pow__() */
+
+ if (!PyArg_ParseTuple(args, "O|O", &other, &third))
+ return NULL;
+ return (*func)(self, other, third);
+}
+
+#undef TERNARY
+#define TERNARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+ {"__" #NAME "__", \
+ (wrapperfunc)wrap_ternaryfunc, \
+ "x.__" #NAME "__(y, z) <==> " #OP}, \
+ {"__r" #NAME "__", \
+ (wrapperfunc)wrap_ternaryfunc, \
+ "y.__r" #NAME "__(x, z) <==> " #OP}, \
+ {0} \
+}
+
+TERNARY(pow, "(x**y) % z");
+
+#undef UNARY
+#define UNARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+ {"__" #NAME "__", \
+ (wrapperfunc)wrap_unaryfunc, \
+ "x.__" #NAME "__() <==> " #OP}, \
+ {0} \
+}
+
+static PyObject *
+wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ unaryfunc func = (unaryfunc)wrapped;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+ return (*func)(self);
+}
+
+UNARY(neg, "-x");
+UNARY(pos, "+x");
+UNARY(abs, "abs(x)");
+UNARY(nonzero, "x != 0");
+UNARY(invert, "~x");
+UNARY(int, "int(x)");
+UNARY(long, "long(x)");
+UNARY(float, "float(x)");
+UNARY(oct, "oct(x)");
+UNARY(hex, "hex(x)");
+
+#undef IBINARY
+#define IBINARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+ {"__" #NAME "__", \
+ (wrapperfunc)wrap_binaryfunc, \
+ "x.__" #NAME "__(y) <==> " #OP}, \
+ {0} \
+}
+
+IBINARY(iadd, "x+=y");
+IBINARY(isub, "x-=y");
+IBINARY(imul, "x*=y");
+IBINARY(idiv, "x/=y");
+IBINARY(imod, "x%=y");
+IBINARY(ilshift, "x<<=y");
+IBINARY(irshift, "x>>=y");
+IBINARY(iand, "x&=y");
+IBINARY(ixor, "x^=y");
+IBINARY(ior, "x|=y");
+
+#undef ITERNARY
+#define ITERNARY(NAME, OP) \
+static struct wrapperbase tab_##NAME[] = { \
+ {"__" #NAME "__", \
+ (wrapperfunc)wrap_ternaryfunc, \
+ "x.__" #NAME "__(y) <==> " #OP}, \
+ {0} \
+}
+
+ITERNARY(ipow, "x = (x**y) % z");
+
+static struct wrapperbase tab_getitem[] = {
+ {"__getitem__", (wrapperfunc)wrap_binaryfunc,
+ "x.__getitem__(y) <==> x[y]"},
+ {0}
+};
+
+static PyObject *
+wrap_intargfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ intargfunc func = (intargfunc)wrapped;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "i", &i))
+ return NULL;
+ return (*func)(self, i);
+}
+
+static struct wrapperbase tab_mul_int[] = {
+ {"__mul__", (wrapperfunc)wrap_intargfunc, "x.__mul__(n) <==> x*n"},
+ {"__rmul__", (wrapperfunc)wrap_intargfunc, "x.__rmul__(n) <==> n*x"},
+ {0}
+};
+
+static struct wrapperbase tab_concat[] = {
+ {"__add__", (wrapperfunc)wrap_binaryfunc, "x.__add__(y) <==> x+y"},
+ {0}
+};
+
+static struct wrapperbase tab_imul_int[] = {
+ {"__imul__", (wrapperfunc)wrap_intargfunc, "x.__imul__(n) <==> x*=n"},
+ {0}
+};
+
+static struct wrapperbase tab_getitem_int[] = {
+ {"__getitem__", (wrapperfunc)wrap_intargfunc,
+ "x.__getitem__(i) <==> x[i]"},
+ {0}
+};
+
+static PyObject *
+wrap_intintargfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ intintargfunc func = (intintargfunc)wrapped;
+ int i, j;
+
+ if (!PyArg_ParseTuple(args, "ii", &i, &j))
+ return NULL;
+ return (*func)(self, i, j);
+}
+
+static struct wrapperbase tab_getslice[] = {
+ {"__getslice__", (wrapperfunc)wrap_intintargfunc,
+ "x.__getslice__(i, j) <==> x[i:j]"},
+ {0}
+};
+
+static PyObject *
+wrap_intobjargproc(PyObject *self, PyObject *args, void *wrapped)
+{
+ intobjargproc func = (intobjargproc)wrapped;
+ int i, res;
+ PyObject *value;
+
+ if (!PyArg_ParseTuple(args, "iO", &i, &value))
+ return NULL;
+ res = (*func)(self, i, value);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct wrapperbase tab_setitem_int[] = {
+ {"__setitem__", (wrapperfunc)wrap_intobjargproc,
+ "x.__setitem__(i, y) <==> x[i]=y"},
+ {0}
+};
+
+static PyObject *
+wrap_intintobjargproc(PyObject *self, PyObject *args, void *wrapped)
+{
+ intintobjargproc func = (intintobjargproc)wrapped;
+ int i, j, res;
+ PyObject *value;
+
+ if (!PyArg_ParseTuple(args, "iiO", &i, &j, &value))
+ return NULL;
+ res = (*func)(self, i, j, value);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct wrapperbase tab_setslice[] = {
+ {"__setslice__", (wrapperfunc)wrap_intintobjargproc,
+ "x.__setslice__(i, j, y) <==> x[i:j]=y"},
+ {0}
+};
+
+/* XXX objobjproc is a misnomer; should be objargpred */
+static PyObject *
+wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped)
+{
+ objobjproc func = (objobjproc)wrapped;
+ int res;
+ PyObject *value;
+
+ if (!PyArg_ParseTuple(args, "O", &value))
+ return NULL;
+ res = (*func)(self, value);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ return PyInt_FromLong((long)res);
+}
+
+static struct wrapperbase tab_contains[] = {
+ {"__contains__", (wrapperfunc)wrap_objobjproc,
+ "x.__contains__(y) <==> y in x"},
+ {0}
+};
+
+static PyObject *
+wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped)
+{
+ objobjargproc func = (objobjargproc)wrapped;
+ int res;
+ PyObject *key, *value;
+
+ if (!PyArg_ParseTuple(args, "OO", &key, &value))
+ return NULL;
+ res = (*func)(self, key, value);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct wrapperbase tab_setitem[] = {
+ {"__setitem__", (wrapperfunc)wrap_objobjargproc,
+ "x.__setitem__(y, z) <==> x[y]=z"},
+ {0}
+};
+
+static PyObject *
+wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ cmpfunc func = (cmpfunc)wrapped;
+ int res;
+ PyObject *other;
+
+ if (!PyArg_ParseTuple(args, "O", &other))
+ return NULL;
+ res = (*func)(self, other);
+ if (PyErr_Occurred())
+ return NULL;
+ return PyInt_FromLong((long)res);
+}
+
+static struct wrapperbase tab_cmp[] = {
+ {"__cmp__", (wrapperfunc)wrap_cmpfunc,
+ "x.__cmp__(y) <==> cmp(x,y)"},
+ {0}
+};
+
+static struct wrapperbase tab_repr[] = {
+ {"__repr__", (wrapperfunc)wrap_unaryfunc,
+ "x.__repr__() <==> repr(x)"},
+ {0}
+};
+
+static struct wrapperbase tab_getattr[] = {
+ {"__getattr__", (wrapperfunc)wrap_binaryfunc,
+ "x.__getattr__('name') <==> x.name"},
+ {0}
+};
+
+static PyObject *
+wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
+{
+ setattrofunc func = (setattrofunc)wrapped;
+ int res;
+ PyObject *name, *value;
+
+ if (!PyArg_ParseTuple(args, "OO", &name, &value))
+ return NULL;
+ res = (*func)(self, name, value);
+ if (res < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_delattr(PyObject *self, PyObject *args, void *wrapped)
+{
+ setattrofunc func = (setattrofunc)wrapped;
+ int res;
+ PyObject *name;
+
+ if (!PyArg_ParseTuple(args, "O", &name))
+ return NULL;
+ res = (*func)(self, name, NULL);
+ if (res < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct wrapperbase tab_setattr[] = {
+ {"__setattr__", (wrapperfunc)wrap_setattr,
+ "x.__setattr__('name', value) <==> x.name = value"},
+ {"__delattr__", (wrapperfunc)wrap_delattr,
+ "x.__delattr__('name') <==> del x.name"},
+ {0}
+};
+
+static PyObject *
+wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ hashfunc func = (hashfunc)wrapped;
+ long res;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+ res = (*func)(self);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ return PyInt_FromLong(res);
+}
+
+static struct wrapperbase tab_hash[] = {
+ {"__hash__", (wrapperfunc)wrap_hashfunc,
+ "x.__hash__() <==> hash(x)"},
+ {0}
+};
+
+static PyObject *
+wrap_call(PyObject *self, PyObject *args, void *wrapped)
+{
+ ternaryfunc func = (ternaryfunc)wrapped;
+
+ /* XXX What about keyword arguments? */
+ return (*func)(self, args, NULL);
+}
+
+static struct wrapperbase tab_call[] = {
+ {"__call__", (wrapperfunc)wrap_call,
+ "x.__call__(...) <==> x(...)"},
+ {0}
+};
+
+static struct wrapperbase tab_str[] = {
+ {"__str__", (wrapperfunc)wrap_unaryfunc,
+ "x.__str__() <==> str(x)"},
+ {0}
+};
+
+static PyObject *
+wrap_richcmpfunc(PyObject *self, PyObject *args, void *wrapped, int op)
+{
+ richcmpfunc func = (richcmpfunc)wrapped;
+ PyObject *other;
+
+ if (!PyArg_ParseTuple(args, "O", &other))
+ return NULL;
+ return (*func)(self, other, op);
+}
+
+#undef RICHCMP_WRAPPER
+#define RICHCMP_WRAPPER(NAME, OP) \
+static PyObject * \
+richcmp_##NAME(PyObject *self, PyObject *args, void *wrapped) \
+{ \
+ return wrap_richcmpfunc(self, args, wrapped, OP); \
+}
+
+RICHCMP_WRAPPER(lt, Py_LT);
+RICHCMP_WRAPPER(le, Py_LE);
+RICHCMP_WRAPPER(eq, Py_EQ);
+RICHCMP_WRAPPER(ne, Py_NE);
+RICHCMP_WRAPPER(gt, Py_GT);
+RICHCMP_WRAPPER(ge, Py_GE);
+
+#undef RICHCMP_ENTRY
+#define RICHCMP_ENTRY(NAME, EXPR) \
+ {"__" #NAME "__", (wrapperfunc)richcmp_##NAME, \
+ "x.__" #NAME "__(y) <==> " EXPR}
+
+static struct wrapperbase tab_richcmp[] = {
+ RICHCMP_ENTRY(lt, "x<y"),
+ RICHCMP_ENTRY(le, "x<=y"),
+ RICHCMP_ENTRY(eq, "x==y"),
+ RICHCMP_ENTRY(ne, "x!=y"),
+ RICHCMP_ENTRY(gt, "x>y"),
+ RICHCMP_ENTRY(ge, "x>=y"),
+ {0}
+};
+
+static struct wrapperbase tab_iter[] = {
+ {"__iter__", (wrapperfunc)wrap_unaryfunc, "x.__iter__() <==> iter(x)"},
+ {0}
+};
+
+static PyObject *
+wrap_next(PyObject *self, PyObject *args, void *wrapped)
+{
+ unaryfunc func = (unaryfunc)wrapped;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+ res = (*func)(self);
+ if (res == NULL && !PyErr_Occurred())
+ PyErr_SetNone(PyExc_StopIteration);
+ return res;
+}
+
+static struct wrapperbase tab_next[] = {
+ {"next", (wrapperfunc)wrap_next,
+ "x.next() -> the next value, or raise StopIteration"},
+ {0}
+};
+
+static PyObject *
+wrap_descr_get(PyObject *self, PyObject *args, void *wrapped)
+{
+ descrgetfunc func = (descrgetfunc)wrapped;
+ PyObject *obj;
+ PyObject *type = NULL;
+
+ if (!PyArg_ParseTuple(args, "O|O", &obj, &type))
+ return NULL;
+ if (type == NULL)
+ type = (PyObject *)obj->ob_type;
+ return (*func)(self, obj, type);
+}
+
+static struct wrapperbase tab_descr_get[] = {
+ {"__get__", (wrapperfunc)wrap_descr_get,
+ "descr.__get__(obj, type) -> value"},
+ {0}
+};
+
+static PyObject *
+wrap_descrsetfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ descrsetfunc func = (descrsetfunc)wrapped;
+ PyObject *obj, *value;
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "OO", &obj, &value))
+ return NULL;
+ ret = (*func)(self, obj, value);
+ if (ret < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct wrapperbase tab_descr_set[] = {
+ {"__set__", (wrapperfunc)wrap_descrsetfunc,
+ "descr.__set__(obj, value)"},
+ {0}
+};
+
+static PyObject *
+wrap_init(PyObject *self, PyObject *args, void *wrapped)
+{
+ initproc func = (initproc)wrapped;
+
+ /* XXX What about keyword arguments? */
+ if (func(self, args, NULL) < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct wrapperbase tab_init[] = {
+ {"__init__", (wrapperfunc)wrap_init,
+ "x.__init__(...) initializes x; "
+ "see x.__type__.__doc__ for signature"},
+ {0}
+};
+
+static PyObject *
+wrap_new(PyObject *type, PyObject *args, void *wrapped)
+{
+ newfunc new = (newfunc)wrapped;
+ return new((PyTypeObject *)type, args, NULL);
+}
+
+static struct wrapperbase tab_new[] = {
+ {"__new__", (wrapperfunc)wrap_new,
+ "T.__new__() -> an object with type T"},
+ {0}
+};
+
+static int
+add_operators(PyTypeObject *type)
+{
+ PySequenceMethods *sq;
+ PyMappingMethods *mp;
+ PyNumberMethods *nb;
+
+#undef ADD
+#define ADD(SLOT, TABLE) \
+ if (SLOT) { \
+ if (add_wrappers(type, TABLE, (void *)(SLOT)) < 0) \
+ return -1; \
+ }
+
+ if ((sq = type->tp_as_sequence) != NULL) {
+ ADD(sq->sq_length, tab_len);
+ ADD(sq->sq_concat, tab_concat);
+ ADD(sq->sq_repeat, tab_mul_int);
+ ADD(sq->sq_item, tab_getitem_int);
+ ADD(sq->sq_slice, tab_getslice);
+ ADD(sq->sq_ass_item, tab_setitem_int);
+ ADD(sq->sq_ass_slice, tab_setslice);
+ ADD(sq->sq_contains, tab_contains);
+ ADD(sq->sq_inplace_concat, tab_iadd);
+ ADD(sq->sq_inplace_repeat, tab_imul_int);
+ }
+
+ if ((mp = type->tp_as_mapping) != NULL) {
+ if (sq->sq_length == NULL)
+ ADD(mp->mp_length, tab_len);
+ ADD(mp->mp_subscript, tab_getitem);
+ ADD(mp->mp_ass_subscript, tab_setitem);
+ }
+
+ /* We don't support "old-style numbers" because their binary
+ operators require that both arguments have the same type;
+ the wrappers here only work for new-style numbers. */
+ if ((type->tp_flags & Py_TPFLAGS_CHECKTYPES) &&
+ (nb = type->tp_as_number) != NULL) {
+ ADD(nb->nb_add, tab_add);
+ ADD(nb->nb_subtract, tab_sub);
+ ADD(nb->nb_multiply, tab_mul);
+ ADD(nb->nb_divide, tab_div);
+ ADD(nb->nb_remainder, tab_mod);
+ ADD(nb->nb_divmod, tab_divmod);
+ ADD(nb->nb_power, tab_pow);
+ ADD(nb->nb_negative, tab_neg);
+ ADD(nb->nb_positive, tab_pos);
+ ADD(nb->nb_absolute, tab_abs);
+ ADD(nb->nb_nonzero, tab_nonzero);
+ ADD(nb->nb_invert, tab_invert);
+ ADD(nb->nb_lshift, tab_lshift);
+ ADD(nb->nb_rshift, tab_rshift);
+ ADD(nb->nb_and, tab_and);
+ ADD(nb->nb_xor, tab_xor);
+ ADD(nb->nb_or, tab_or);
+ /* We don't support coerce() -- see above comment */
+ ADD(nb->nb_int, tab_int);
+ ADD(nb->nb_long, tab_long);
+ ADD(nb->nb_float, tab_float);
+ ADD(nb->nb_oct, tab_oct);
+ ADD(nb->nb_hex, tab_hex);
+ ADD(nb->nb_inplace_add, tab_iadd);
+ ADD(nb->nb_inplace_subtract, tab_isub);
+ ADD(nb->nb_inplace_multiply, tab_imul);
+ ADD(nb->nb_inplace_divide, tab_idiv);
+ ADD(nb->nb_inplace_remainder, tab_imod);
+ ADD(nb->nb_inplace_power, tab_ipow);
+ ADD(nb->nb_inplace_lshift, tab_ilshift);
+ ADD(nb->nb_inplace_rshift, tab_irshift);
+ ADD(nb->nb_inplace_and, tab_iand);
+ ADD(nb->nb_inplace_xor, tab_ixor);
+ ADD(nb->nb_inplace_or, tab_ior);
+ }
+
+ ADD(type->tp_getattro, tab_getattr);
+ ADD(type->tp_setattro, tab_setattr);
+ ADD(type->tp_compare, tab_cmp);
+ ADD(type->tp_repr, tab_repr);
+ ADD(type->tp_hash, tab_hash);
+ ADD(type->tp_call, tab_call);
+ ADD(type->tp_str, tab_str);
+ ADD(type->tp_richcompare, tab_richcmp);
+ ADD(type->tp_iter, tab_iter);
+ ADD(type->tp_iternext, tab_next);
+ ADD(type->tp_descr_get, tab_descr_get);
+ ADD(type->tp_descr_set, tab_descr_set);
+ ADD(type->tp_init, tab_init);
+
+ if (type->tp_new != NULL)
+ add_staticmethodwrappers(type, tab_new,
+ (void *)(type->tp_new));
+
+ return 0;
+}
+
+/* Slot wrappers that call the corresponding __foo__ slot */
+
+#define SLOT0(SLOTNAME, OPNAME) \
+static PyObject * \
+slot_##SLOTNAME(PyObject *self) \
+{ \
+ return PyObject_CallMethod(self, "__" #OPNAME "__", ""); \
+}
+
+#define SLOT1(SLOTNAME, OPNAME, ARG1TYPE, ARGCODES) \
+static PyObject * \
+slot_##SLOTNAME(PyObject *self, ARG1TYPE arg1) \
+{ \
+ return PyObject_CallMethod(self, "__" #OPNAME "__", #ARGCODES, arg1); \
+}
+
+#define SLOT2(SLOTNAME, OPNAME, ARG1TYPE, ARG2TYPE, ARGCODES) \
+static PyObject * \
+slot_##SLOTNAME(PyObject *self, ARG1TYPE arg1, ARG2TYPE arg2) \
+{ \
+ return PyObject_CallMethod(self, "__" #OPNAME "__", \
+ #ARGCODES, arg1, arg2); \
+}
+
+static int
+slot_sq_length(PyObject *self)
+{
+ PyObject *res = PyObject_CallMethod(self, "__len__", "");
+
+ if (res == NULL)
+ return -1;
+ return (int)PyInt_AsLong(res);
+}
+
+SLOT1(sq_concat, add, PyObject *, O);
+SLOT1(sq_repeat, mul, int, i);
+SLOT1(sq_item, getitem, int, i);
+SLOT2(sq_slice, getslice, int, int, ii);
+
+static int
+slot_sq_ass_item(PyObject *self, int index, PyObject *value)
+{
+ PyObject *res;
+
+ if (value == NULL)
+ res = PyObject_CallMethod(self, "__delitem__", "i", index);
+ else
+ res = PyObject_CallMethod(self, "__setitem__",
+ "iO", index, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+static int
+slot_sq_ass_slice(PyObject *self, int i, int j, PyObject *value)
+{
+ PyObject *res;
+
+ if (value == NULL)
+ res = PyObject_CallMethod(self, "__delslice__", "ii", i, j);
+ else
+ res = PyObject_CallMethod(self, "__setslice__",
+ "iiO", i, j, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+static int
+slot_sq_contains(PyObject *self, PyObject *value)
+{
+ PyObject *res = PyObject_CallMethod(self, "__contains__", "O", value);
+ int r;
+
+ if (res == NULL)
+ return -1;
+ r = PyInt_AsLong(res);
+ Py_DECREF(res);
+ return r;
+}
+
+SLOT1(sq_inplace_concat, iadd, PyObject *, O);
+SLOT1(sq_inplace_repeat, imul, int, i);
+
+#define slot_mp_length slot_sq_length
+
+SLOT1(mp_subscript, getitem, PyObject *, O);
+
+static int
+slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value)
+{
+ PyObject *res;
+
+ if (value == NULL)
+ res = PyObject_CallMethod(self, "__delitem__", "O", key);
+ else
+ res = PyObject_CallMethod(self, "__setitem__",
+ "OO", key, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+/* XXX the numerical slots should call the reverse operators too;
+ but how do they know their type? */
+SLOT1(nb_add, add, PyObject *, O);
+SLOT1(nb_subtract, sub, PyObject *, O);
+SLOT1(nb_multiply, mul, PyObject *, O);
+SLOT1(nb_divide, div, PyObject *, O);
+SLOT1(nb_remainder, mod, PyObject *, O);
+SLOT1(nb_divmod, divmod, PyObject *, O);
+SLOT2(nb_power, pow, PyObject *, PyObject *, OO);
+SLOT0(nb_negative, neg);
+SLOT0(nb_positive, pos);
+SLOT0(nb_absolute, abs);
+
+static int
+slot_nb_nonzero(PyObject *self)
+{
+ PyObject *res = PyObject_CallMethod(self, "__nonzero__", "");
+
+ if (res == NULL)
+ return -1;
+ return (int)PyInt_AsLong(res);
+}
+
+SLOT0(nb_invert, invert);
+SLOT1(nb_lshift, lshift, PyObject *, O);
+SLOT1(nb_rshift, rshift, PyObject *, O);
+SLOT1(nb_and, and, PyObject *, O);
+SLOT1(nb_xor, xor, PyObject *, O);
+SLOT1(nb_or, or, PyObject *, O);
+/* Not coerce() */
+SLOT0(nb_int, int);
+SLOT0(nb_long, long);
+SLOT0(nb_float, float);
+SLOT0(nb_oct, oct);
+SLOT0(nb_hex, hex);
+SLOT1(nb_inplace_add, iadd, PyObject *, O);
+SLOT1(nb_inplace_subtract, isub, PyObject *, O);
+SLOT1(nb_inplace_multiply, imul, PyObject *, O);
+SLOT1(nb_inplace_divide, idiv, PyObject *, O);
+SLOT1(nb_inplace_remainder, imod, PyObject *, O);
+SLOT2(nb_inplace_power, ipow, PyObject *, PyObject *, OO);
+SLOT1(nb_inplace_lshift, ilshift, PyObject *, O);
+SLOT1(nb_inplace_rshift, irshift, PyObject *, O);
+SLOT1(nb_inplace_and, iand, PyObject *, O);
+SLOT1(nb_inplace_xor, ixor, PyObject *, O);
+SLOT1(nb_inplace_or, ior, PyObject *, O);
+
+static int
+slot_tp_compare(PyObject *self, PyObject *other)
+{
+ PyObject *res = PyObject_CallMethod(self, "__cmp__", "O", other);
+ long r;
+
+ if (res == NULL)
+ return -1;
+ r = PyInt_AsLong(res);
+ Py_DECREF(res);
+ return (int)r;
+}
+
+SLOT0(tp_repr, repr);
+
+static long
+slot_tp_hash(PyObject *self)
+{
+ PyObject *res = PyObject_CallMethod(self, "__hash__", "");
+ long h;
+
+ if (res == NULL)
+ return -1;
+ h = PyInt_AsLong(res);
+ if (h == -1 && !PyErr_Occurred())
+ h = -2;
+ return h;
+}
+
+static PyObject *
+slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *meth = PyObject_GetAttrString(self, "__call__");
+ PyObject *res;
+
+ if (meth == NULL)
+ return NULL;
+ res = PyObject_Call(meth, args, kwds);
+ Py_DECREF(meth);
+ return res;
+}
+
+SLOT0(tp_str, str);
+
+static PyObject *
+slot_tp_getattro(PyObject *self, PyObject *name)
+{
+ PyTypeObject *tp = self->ob_type;
+ PyObject *dict = NULL;
+ PyObject *getattr;
+
+ if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ dict = tp->tp_dict;
+ if (dict == NULL) {
+ PyErr_Format(PyExc_SystemError,
+ "'%.100s' type object has no __dict__???",
+ tp->tp_name);
+ return NULL;
+ }
+ getattr = PyDict_GetItemString(dict, "__getattr__");
+ if (getattr == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "__getattr__");
+ return NULL;
+ }
+ return PyObject_CallFunction(getattr, "OO", self, name);
+}
+
+static int
+slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value)
+{
+ PyObject *res;
+
+ if (value == NULL)
+ res = PyObject_CallMethod(self, "__delattr__", "O", name);
+ else
+ res = PyObject_CallMethod(self, "__setattr__",
+ "OO", name, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+/* Map rich comparison operators to their __xx__ namesakes */
+static char *name_op[] = {
+ "__lt__",
+ "__le__",
+ "__eq__",
+ "__ne__",
+ "__gt__",
+ "__ge__",
};
+
+static PyObject *
+slot_tp_richcompare(PyObject *self, PyObject *other, int op)
+{
+ PyObject *meth = PyObject_GetAttrString(self, name_op[op]);
+ PyObject *res;
+
+ if (meth == NULL)
+ return NULL;
+ res = PyObject_CallFunction(meth, "O", other);
+ Py_DECREF(meth);
+ return res;
+}
+
+SLOT0(tp_iter, iter);
+
+static PyObject *
+slot_tp_iternext(PyObject *self)
+{
+ return PyObject_CallMethod(self, "next", "");
+}
+
+SLOT2(tp_descr_get, get, PyObject *, PyObject *, OO);
+
+static int
+slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value)
+{
+ PyObject *res = PyObject_CallMethod(self, "__set__",
+ "OO", target, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+static int
+slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *meth = PyObject_GetAttrString(self, "__init__");
+ PyObject *res;
+
+ if (meth == NULL)
+ return -1;
+ res = PyObject_Call(meth, args, kwds);
+ Py_DECREF(meth);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+static PyObject *
+slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *func = PyObject_GetAttrString((PyObject *)type, "__new__");
+ PyObject *newargs, *x;
+ int i, n;
+
+ if (func == NULL)
+ return NULL;
+ assert(PyTuple_Check(args));
+ n = PyTuple_GET_SIZE(args);
+ newargs = PyTuple_New(n+1);
+ if (newargs == NULL)
+ return NULL;
+ Py_INCREF(type);
+ PyTuple_SET_ITEM(newargs, 0, (PyObject *)type);
+ for (i = 0; i < n; i++) {
+ x = PyTuple_GET_ITEM(args, i);
+ Py_INCREF(x);
+ PyTuple_SET_ITEM(newargs, i+1, x);
+ }
+ x = PyObject_Call(func, newargs, kwds);
+ Py_DECREF(func);
+ return x;
+}
+
+static void
+override_slots(PyTypeObject *type, PyObject *dict)
+{
+ PySequenceMethods *sq = type->tp_as_sequence;
+ PyMappingMethods *mp = type->tp_as_mapping;
+ PyNumberMethods *nb = type->tp_as_number;
+
+#define SQSLOT(OPNAME, SLOTNAME) \
+ if (PyDict_GetItemString(dict, OPNAME)) { \
+ sq->SLOTNAME = slot_##SLOTNAME; \
+ }
+
+#define MPSLOT(OPNAME, SLOTNAME) \
+ if (PyDict_GetItemString(dict, OPNAME)) { \
+ mp->SLOTNAME = slot_##SLOTNAME; \
+ }
+
+#define NBSLOT(OPNAME, SLOTNAME) \
+ if (PyDict_GetItemString(dict, OPNAME)) { \
+ nb->SLOTNAME = slot_##SLOTNAME; \
+ }
+
+#define TPSLOT(OPNAME, SLOTNAME) \
+ if (PyDict_GetItemString(dict, OPNAME)) { \
+ type->SLOTNAME = slot_##SLOTNAME; \
+ }
+
+ SQSLOT("__len__", sq_length);
+ SQSLOT("__add__", sq_concat);
+ SQSLOT("__mul__", sq_repeat);
+ SQSLOT("__getitem__", sq_item);
+ SQSLOT("__getslice__", sq_slice);
+ SQSLOT("__setitem__", sq_ass_item);
+ SQSLOT("__delitem__", sq_ass_item);
+ SQSLOT("__setslice__", sq_ass_slice);
+ SQSLOT("__delslice__", sq_ass_slice);
+ SQSLOT("__contains__", sq_contains);
+ SQSLOT("__iadd__", sq_inplace_concat);
+ SQSLOT("__imul__", sq_inplace_repeat);
+
+ MPSLOT("__len__", mp_length);
+ MPSLOT("__getitem__", mp_subscript);
+ MPSLOT("__setitem__", mp_ass_subscript);
+ MPSLOT("__delitem__", mp_ass_subscript);
+
+ NBSLOT("__add__", nb_add);
+ NBSLOT("__sub__", nb_subtract);
+ NBSLOT("__mul__", nb_multiply);
+ NBSLOT("__div__", nb_divide);
+ NBSLOT("__mod__", nb_remainder);
+ NBSLOT("__divmod__", nb_divmod);
+ NBSLOT("__pow__", nb_power);
+ NBSLOT("__neg__", nb_negative);
+ NBSLOT("__pos__", nb_positive);
+ NBSLOT("__abs__", nb_absolute);
+ NBSLOT("__nonzero__", nb_nonzero);
+ NBSLOT("__invert__", nb_invert);
+ NBSLOT("__lshift__", nb_lshift);
+ NBSLOT("__rshift__", nb_rshift);
+ NBSLOT("__and__", nb_and);
+ NBSLOT("__xor__", nb_xor);
+ NBSLOT("__or__", nb_or);
+ /* Not coerce() */
+ NBSLOT("__int__", nb_int);
+ NBSLOT("__long__", nb_long);
+ NBSLOT("__float__", nb_float);
+ NBSLOT("__oct__", nb_oct);
+ NBSLOT("__hex__", nb_hex);
+ NBSLOT("__iadd__", nb_inplace_add);
+ NBSLOT("__isub__", nb_inplace_subtract);
+ NBSLOT("__imul__", nb_inplace_multiply);
+ NBSLOT("__idiv__", nb_inplace_divide);
+ NBSLOT("__imod__", nb_inplace_remainder);
+ NBSLOT("__ipow__", nb_inplace_power);
+ NBSLOT("__ilshift__", nb_inplace_lshift);
+ NBSLOT("__irshift__", nb_inplace_rshift);
+ NBSLOT("__iand__", nb_inplace_and);
+ NBSLOT("__ixor__", nb_inplace_xor);
+ NBSLOT("__ior__", nb_inplace_or);
+
+ if (PyDict_GetItemString(dict, "__str__") ||
+ PyDict_GetItemString(dict, "__repr__"))
+ type->tp_print = NULL;
+
+ TPSLOT("__cmp__", tp_compare);
+ TPSLOT("__repr__", tp_repr);
+ TPSLOT("__hash__", tp_hash);
+ TPSLOT("__call__", tp_call);
+ TPSLOT("__str__", tp_str);
+ TPSLOT("__getattr__", tp_getattro);
+ TPSLOT("__setattr__", tp_setattro);
+ TPSLOT("__lt__", tp_richcompare);
+ TPSLOT("__le__", tp_richcompare);
+ TPSLOT("__eq__", tp_richcompare);
+ TPSLOT("__ne__", tp_richcompare);
+ TPSLOT("__gt__", tp_richcompare);
+ TPSLOT("__ge__", tp_richcompare);
+ TPSLOT("__iter__", tp_iter);
+ TPSLOT("next", tp_iternext);
+ TPSLOT("__get__", tp_descr_get);
+ TPSLOT("__set__", tp_descr_set);
+ TPSLOT("__init__", tp_init);
+ TPSLOT("__new__", tp_new);
+}
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 4bdff5a..1319c7c 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -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 */