Big internal change that should have no external effects: unify the

'slotdef' structure typedef and 'struct wrapperbase'.  By adding the
wrapper docstrings to the slotdef structure, the slotdefs array can
serve as the data structure that drives add_operators(); the wrapper
descriptor contains a pointer to slotdef structure.  This replaces
lots of custom code from add_operators() by a loop over the slotdefs
array, and does away with all the tab_xxx tables.
This commit is contained in:
Guido van Rossum 2001-10-21 00:44:31 +00:00
parent 971e78b55b
commit 6d204074cb
2 changed files with 244 additions and 525 deletions

View File

@ -16,8 +16,11 @@ typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
struct wrapperbase { struct wrapperbase {
char *name; char *name;
int offset;
void *function;
wrapperfunc wrapper; wrapperfunc wrapper;
char *doc; char *doc;
PyObject *name_strobj;
}; };
/* Various kinds of descriptor objects */ /* Various kinds of descriptor objects */

View File

@ -1893,11 +1893,6 @@ wrap_inquiry(PyObject *self, PyObject *args, void *wrapped)
return PyInt_FromLong((long)res); return PyInt_FromLong((long)res);
} }
static struct wrapperbase tab_len[] = {
{"__len__", (wrapperfunc)wrap_inquiry, "x.__len__() <==> len(x)"},
{0}
};
static PyObject * static PyObject *
wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped) wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -1941,30 +1936,6 @@ wrap_binaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
return (*func)(other, self); return (*func)(other, self);
} }
#undef BINARY
#define BINARY(NAME, OP) \
static struct wrapperbase tab_##NAME[] = { \
{"__" #NAME "__", \
(wrapperfunc)wrap_binaryfunc_l, \
"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 * static PyObject *
wrap_coercefunc(PyObject *self, PyObject *args, void *wrapped) wrap_coercefunc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -1992,15 +1963,6 @@ wrap_coercefunc(PyObject *self, PyObject *args, void *wrapped)
return res; return res;
} }
static struct wrapperbase tab_coerce[] = {
{"__coerce__", (wrapperfunc)wrap_coercefunc,
"x.__coerce__(y) <==> coerce(x, y)"},
{0}
};
BINARY(floordiv, "x//y");
BINARY(truediv, "x/y # true division");
static PyObject * static PyObject *
wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped) wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2029,29 +1991,6 @@ wrap_ternaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
return (*func)(other, self, third); return (*func)(other, self, 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_r, \
"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 * static PyObject *
wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped) wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2062,56 +2001,6 @@ wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped)
return (*func)(self); 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");
IBINARY(ifloordiv, "x//=y");
IBINARY(itruediv, "x/=y # true division");
#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 * static PyObject *
wrap_intargfunc(PyObject *self, PyObject *args, void *wrapped) wrap_intargfunc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2123,22 +2012,6 @@ wrap_intargfunc(PyObject *self, PyObject *args, void *wrapped)
return (*func)(self, i); 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 int static int
getindex(PyObject *self, PyObject *arg) getindex(PyObject *self, PyObject *arg)
{ {
@ -2178,12 +2051,6 @@ wrap_sq_item(PyObject *self, PyObject *args, void *wrapped)
return NULL; return NULL;
} }
static struct wrapperbase tab_getitem_int[] = {
{"__getitem__", (wrapperfunc)wrap_sq_item,
"x.__getitem__(i) <==> x[i]"},
{0}
};
static PyObject * static PyObject *
wrap_intintargfunc(PyObject *self, PyObject *args, void *wrapped) wrap_intintargfunc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2195,12 +2062,6 @@ wrap_intintargfunc(PyObject *self, PyObject *args, void *wrapped)
return (*func)(self, i, j); return (*func)(self, i, j);
} }
static struct wrapperbase tab_getslice[] = {
{"__getslice__", (wrapperfunc)wrap_intintargfunc,
"x.__getslice__(i, j) <==> x[i:j]"},
{0}
};
static PyObject * static PyObject *
wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped) wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2239,14 +2100,6 @@ wrap_sq_delitem(PyObject *self, PyObject *args, void *wrapped)
return Py_None; return Py_None;
} }
static struct wrapperbase tab_setitem_int[] = {
{"__setitem__", (wrapperfunc)wrap_sq_setitem,
"x.__setitem__(i, y) <==> x[i]=y"},
{"__delitem__", (wrapperfunc)wrap_sq_delitem,
"x.__delitem__(y) <==> del x[y]"},
{0}
};
static PyObject * static PyObject *
wrap_intintobjargproc(PyObject *self, PyObject *args, void *wrapped) wrap_intintobjargproc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2278,14 +2131,6 @@ wrap_delslice(PyObject *self, PyObject *args, void *wrapped)
return Py_None; return Py_None;
} }
static struct wrapperbase tab_setslice[] = {
{"__setslice__", (wrapperfunc)wrap_intintobjargproc,
"x.__setslice__(i, j, y) <==> x[i:j]=y"},
{"__delslice__", (wrapperfunc)wrap_delslice,
"x.__delslice__(i, j) <==> del x[i:j]"},
{0}
};
/* XXX objobjproc is a misnomer; should be objargpred */ /* XXX objobjproc is a misnomer; should be objargpred */
static PyObject * static PyObject *
wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped) wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped)
@ -2302,12 +2147,6 @@ wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped)
return PyInt_FromLong((long)res); return PyInt_FromLong((long)res);
} }
static struct wrapperbase tab_contains[] = {
{"__contains__", (wrapperfunc)wrap_objobjproc,
"x.__contains__(y) <==> y in x"},
{0}
};
static PyObject * static PyObject *
wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped) wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2340,14 +2179,6 @@ wrap_delitem(PyObject *self, PyObject *args, void *wrapped)
return Py_None; return Py_None;
} }
static struct wrapperbase tab_setitem[] = {
{"__setitem__", (wrapperfunc)wrap_objobjargproc,
"x.__setitem__(y, z) <==> x[y]=z"},
{"__delitem__", (wrapperfunc)wrap_delitem,
"x.__delitem__(y) <==> del x[y]"},
{0}
};
static PyObject * static PyObject *
wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped) wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2373,24 +2204,6 @@ wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped)
return PyInt_FromLong((long)res); 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[] = {
{"__getattribute__", (wrapperfunc)wrap_binaryfunc,
"x.__getattribute__('name') <==> x.name"},
{0}
};
static PyObject * static PyObject *
wrap_setattr(PyObject *self, PyObject *args, void *wrapped) wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2423,14 +2236,6 @@ wrap_delattr(PyObject *self, PyObject *args, void *wrapped)
return 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 * static PyObject *
wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped) wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2445,12 +2250,6 @@ wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped)
return PyInt_FromLong(res); return PyInt_FromLong(res);
} }
static struct wrapperbase tab_hash[] = {
{"__hash__", (wrapperfunc)wrap_hashfunc,
"x.__hash__() <==> hash(x)"},
{0}
};
static PyObject * static PyObject *
wrap_call(PyObject *self, PyObject *args, void *wrapped) wrap_call(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2460,18 +2259,6 @@ wrap_call(PyObject *self, PyObject *args, void *wrapped)
return (*func)(self, args, NULL); 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 * static PyObject *
wrap_richcmpfunc(PyObject *self, PyObject *args, void *wrapped, int op) wrap_richcmpfunc(PyObject *self, PyObject *args, void *wrapped, int op)
{ {
@ -2498,26 +2285,6 @@ RICHCMP_WRAPPER(ne, Py_NE)
RICHCMP_WRAPPER(gt, Py_GT) RICHCMP_WRAPPER(gt, Py_GT)
RICHCMP_WRAPPER(ge, Py_GE) 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 * static PyObject *
wrap_next(PyObject *self, PyObject *args, void *wrapped) wrap_next(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2532,12 +2299,6 @@ wrap_next(PyObject *self, PyObject *args, void *wrapped)
return res; return res;
} }
static struct wrapperbase tab_next[] = {
{"next", (wrapperfunc)wrap_next,
"x.next() -> the next value, or raise StopIteration"},
{0}
};
static PyObject * static PyObject *
wrap_descr_get(PyObject *self, PyObject *args, void *wrapped) wrap_descr_get(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2550,12 +2311,6 @@ wrap_descr_get(PyObject *self, PyObject *args, void *wrapped)
return (*func)(self, obj, 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 * static PyObject *
wrap_descr_set(PyObject *self, PyObject *args, void *wrapped) wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2572,12 +2327,6 @@ wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
return Py_None; return Py_None;
} }
static struct wrapperbase tab_descr_set[] = {
{"__set__", (wrapperfunc)wrap_descr_set,
"descr.__set__(obj, value)"},
{0}
};
static PyObject * static PyObject *
wrap_init(PyObject *self, PyObject *args, void *wrapped) wrap_init(PyObject *self, PyObject *args, void *wrapped)
{ {
@ -2590,13 +2339,6 @@ wrap_init(PyObject *self, PyObject *args, void *wrapped)
return Py_None; return Py_None;
} }
static struct wrapperbase tab_init[] = {
{"__init__", (wrapperfunc)wrap_init,
"x.__init__(...) initializes x; "
"see x.__class__.__doc__ for signature"},
{0}
};
static PyObject * static PyObject *
tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds) tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
{ {
@ -2673,145 +2415,6 @@ add_tp_new_wrapper(PyTypeObject *type)
return PyDict_SetItemString(type->tp_dict, "__new__", func); return PyDict_SetItemString(type->tp_dict, "__new__", func);
} }
static int
add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
{
PyObject *dict = type->tp_dict;
for (; wraps->name != NULL; wraps++) {
PyObject *descr;
if (PyDict_GetItemString(dict, wraps->name))
continue;
descr = PyDescr_NewWrapper(type, wraps, wrapped);
if (descr == NULL)
return -1;
if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
return -1;
Py_DECREF(descr);
}
return 0;
}
/* This function is called by PyType_Ready() to populate the type's
dictionary with method descriptors for function slots. For each
function slot (like tp_repr) that's defined in the type, one or
more corresponding descriptors are added in the type's tp_dict
dictionary under the appropriate name (like __repr__). Some
function slots cause more than one descriptor to be added (for
example, the nb_add slot adds both __add__ and __radd__
descriptors) and some function slots compete for the same
descriptor (for example both sq_item and mp_subscript generate a
__getitem__ descriptor). This only adds new descriptors and
doesn't overwrite entries in tp_dict that were previously
defined. The descriptors contain a reference to the C function
they must call, so that it's safe if they are copied into a
subtype's __dict__ and the subtype has a different C function in
its slot -- calling the method defined by the descriptor will call
the C function that was used to create it, rather than the C
function present in the slot when it is called. (This is important
because a subtype may have a C function in the slot that calls the
method from the dictionary, and we want to avoid infinite recursion
here.) */
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);
}
if ((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);
ADD(nb->nb_coerce, tab_coerce);
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);
if (type->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
ADD(nb->nb_floor_divide, tab_floordiv);
ADD(nb->nb_true_divide, tab_truediv);
ADD(nb->nb_inplace_floor_divide, tab_ifloordiv);
ADD(nb->nb_inplace_true_divide, tab_itruediv);
}
}
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) {
if (add_tp_new_wrapper(type) < 0)
return -1;
}
return 0;
}
/* Slot wrappers that call the corresponding __foo__ slot. See comments /* Slot wrappers that call the corresponding __foo__ slot. See comments
below at override_slots() for more explanation. */ below at override_slots() for more explanation. */
@ -3571,155 +3174,216 @@ slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
__ne__ etc. all map to tp_richcompare) and one name may map to multiple __ne__ etc. all map to tp_richcompare) and one name may map to multiple
slots (e.g. __str__ affects tp_str as well as tp_repr). */ slots (e.g. __str__ affects tp_str as well as tp_repr). */
typedef struct { typedef struct wrapperbase slotdef;
char *name;
int offset;
void *function;
wrapperfunc wrapper;
PyObject *name_strobj;
} slotdef;
#undef TPSLOT #undef TPSLOT
#undef ETSLOT #undef ETSLOT
#undef SQSLOT #undef SQSLOT
#undef MPSLOT #undef MPSLOT
#undef NBSLOT #undef NBSLOT
#undef UNSLOT
#undef IBSLOT
#undef BINSLOT #undef BINSLOT
#undef RBINSLOT #undef RBINSLOT
#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER) \ #define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER} {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, DOC}
#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER) \ #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{NAME, offsetof(etype, SLOT), (void *)(FUNCTION), WRAPPER} {NAME, offsetof(etype, SLOT), (void *)(FUNCTION), WRAPPER, DOC}
#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER) \ #define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER) ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, DOC)
#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER) \ #define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER) ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER, DOC)
#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER) \ #define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER) ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC)
#define BINSLOT(NAME, SLOT, FUNCTION) \ #define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l) ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \
#define RBINSLOT(NAME, SLOT, FUNCTION) \ "x." NAME "() <==> " DOC)
ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r) #define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \
"x." NAME "(y) <==> x" DOC "y")
#define BINSLOT(NAME, SLOT, FUNCTION, DOC) \
ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \
"x." NAME "(y) <==> x" DOC "y")
#define RBINSLOT(NAME, SLOT, FUNCTION, DOC) \
ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \
"x." NAME "(y) <==> y" DOC "x")
static slotdef slotdefs[] = { static slotdef slotdefs[] = {
SQSLOT("__len__", sq_length, slot_sq_length, wrap_inquiry), SQSLOT("__len__", sq_length, slot_sq_length, wrap_inquiry,
SQSLOT("__add__", sq_concat, slot_sq_concat, wrap_binaryfunc), "x.__len__() <==> len(x)"),
SQSLOT("__mul__", sq_repeat, slot_sq_repeat, wrap_intargfunc), SQSLOT("__add__", sq_concat, slot_sq_concat, wrap_binaryfunc,
SQSLOT("__rmul__", sq_repeat, slot_sq_repeat, wrap_intargfunc), "x.__add__(y) <==> x+y"),
SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item), SQSLOT("__mul__", sq_repeat, slot_sq_repeat, wrap_intargfunc,
SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_intintargfunc), "x.__mul__(n) <==> x*n"),
SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem), SQSLOT("__rmul__", sq_repeat, slot_sq_repeat, wrap_intargfunc,
SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem), "x.__rmul__(n) <==> n*x"),
SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
"x.__getitem__(y) <==> x[y]"),
SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_intintargfunc,
"x.__getslice__(i, j) <==> x[i:j]"),
SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem,
"x.__setitem__(i, y) <==> x[i]=y"),
SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem,
"x.__delitem__(y) <==> del x[y]"),
SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice, SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice,
wrap_intintobjargproc), wrap_intintobjargproc,
SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice), "x.__setslice__(i, j, y) <==> x[i:j]=y"),
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc), SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice,
"x.__delslice__(i, j) <==> del x[i:j]"),
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
"x.__contains__(y) <==> y in x"),
SQSLOT("__iadd__", sq_inplace_concat, slot_sq_inplace_concat, SQSLOT("__iadd__", sq_inplace_concat, slot_sq_inplace_concat,
wrap_binaryfunc), wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
SQSLOT("__imul__", sq_inplace_repeat, slot_sq_inplace_repeat, SQSLOT("__imul__", sq_inplace_repeat, slot_sq_inplace_repeat,
wrap_intargfunc), wrap_intargfunc, "x.__imul__(y) <==> x*=y"),
MPSLOT("__len__", mp_length, slot_mp_length, wrap_inquiry), MPSLOT("__len__", mp_length, slot_mp_length, wrap_inquiry,
"x.__len__() <==> len(x)"),
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
wrap_binaryfunc), wrap_binaryfunc,
"x.__getitem__(y) <==> x[y]"),
MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript, MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
wrap_objobjargproc), wrap_objobjargproc,
"x.__setitem__(i, y) <==> x[i]=y"),
MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript, MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
wrap_delitem), wrap_delitem,
"x.__delitem__(y) <==> del x[y]"),
BINSLOT("__add__", nb_add, slot_nb_add), BINSLOT("__add__", nb_add, slot_nb_add,
RBINSLOT("__radd__", nb_add, slot_nb_add), "+"),
BINSLOT("__sub__", nb_subtract, slot_nb_subtract), RBINSLOT("__radd__", nb_add, slot_nb_add,
RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract), "+"),
BINSLOT("__mul__", nb_multiply, slot_nb_multiply), BINSLOT("__sub__", nb_subtract, slot_nb_subtract,
RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply), "-"),
BINSLOT("__div__", nb_divide, slot_nb_divide), RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract,
RBINSLOT("__rdiv__", nb_divide, slot_nb_divide), "-"),
BINSLOT("__mod__", nb_remainder, slot_nb_remainder), BINSLOT("__mul__", nb_multiply, slot_nb_multiply,
RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder), "*"),
BINSLOT("__divmod__", nb_divmod, slot_nb_divmod), RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply,
RBINSLOT("__rdivmod__", nb_divmod, slot_nb_divmod), "*"),
NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc), BINSLOT("__div__", nb_divide, slot_nb_divide,
NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r), "/"),
NBSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc), RBINSLOT("__rdiv__", nb_divide, slot_nb_divide,
NBSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc), "/"),
NBSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc), BINSLOT("__mod__", nb_remainder, slot_nb_remainder,
NBSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_unaryfunc), "%"),
NBSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc), RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder,
BINSLOT("__lshift__", nb_lshift, slot_nb_lshift), "%"),
RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift), BINSLOT("__divmod__", nb_divmod, slot_nb_divmod,
BINSLOT("__rshift__", nb_rshift, slot_nb_rshift), "divmod(x, y)"),
RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift), RBINSLOT("__rdivmod__", nb_divmod, slot_nb_divmod,
BINSLOT("__and__", nb_and, slot_nb_and), "divmod(y, x)"),
RBINSLOT("__rand__", nb_and, slot_nb_and), NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc,
BINSLOT("__xor__", nb_xor, slot_nb_xor), "x.__pow__(y[, z]) <==> pow(x, y[, z])"),
RBINSLOT("__rxor__", nb_xor, slot_nb_xor), NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r,
BINSLOT("__or__", nb_or, slot_nb_or), "y.__rpow__(x[, z]) <==> pow(x, y[, z])"),
RBINSLOT("__ror__", nb_or, slot_nb_or), UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-x"),
NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc), UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+x"),
NBSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc), UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc,
NBSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc), "abs(x)"),
NBSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc), UNSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_unaryfunc,
NBSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc), "x != 0"),
NBSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc), UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~x"),
NBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add, BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"),
wrap_binaryfunc), RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"),
NBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract, BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"),
wrap_binaryfunc), RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift, ">>"),
NBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply, BINSLOT("__and__", nb_and, slot_nb_and, "&"),
wrap_binaryfunc), RBINSLOT("__rand__", nb_and, slot_nb_and, "&"),
NBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide, BINSLOT("__xor__", nb_xor, slot_nb_xor, "^"),
wrap_binaryfunc), RBINSLOT("__rxor__", nb_xor, slot_nb_xor, "^"),
NBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder, BINSLOT("__or__", nb_or, slot_nb_or, "|"),
wrap_binaryfunc), RBINSLOT("__ror__", nb_or, slot_nb_or, "|"),
NBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power, NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc,
wrap_ternaryfunc), "x.__coerce__(y) <==> coerce(x, y)"),
NBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift, UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc,
wrap_binaryfunc), "int(x)"),
NBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift, UNSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc,
wrap_binaryfunc), "long(x)"),
NBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and, UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc,
wrap_binaryfunc), "float(x)"),
NBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor, UNSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc,
wrap_binaryfunc), "oct(x)"),
NBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or, UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
wrap_binaryfunc), "hex(x)"),
BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide), IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide), wrap_binaryfunc, "+"),
BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide), IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide), wrap_binaryfunc, "-"),
NBSLOT("__ifloordiv__", nb_inplace_floor_divide, IBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply,
slot_nb_inplace_floor_divide, wrap_binaryfunc), wrap_binaryfunc, "*"),
NBSLOT("__itruediv__", nb_inplace_true_divide, IBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide,
slot_nb_inplace_true_divide, wrap_binaryfunc), wrap_binaryfunc, "/"),
IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder,
wrap_binaryfunc, "%"),
IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power,
wrap_ternaryfunc, "**"),
IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift,
wrap_binaryfunc, "<<"),
IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift,
wrap_binaryfunc, ">>"),
IBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and,
wrap_binaryfunc, "&"),
IBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor,
wrap_binaryfunc, "^"),
IBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or,
wrap_binaryfunc, "|"),
BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide, "//"),
RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide, "//"),
BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide, "/"),
RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide, "/"),
IBSLOT("__ifloordiv__", nb_inplace_floor_divide,
slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"),
IBSLOT("__itruediv__", nb_inplace_true_divide,
slot_nb_inplace_true_divide, wrap_binaryfunc, "/"),
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc), TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc), "x.__str__() <==> str(x)"),
TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc), TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc,
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc), "x.__repr__() <==> repr(x)"),
TPSLOT("__call__", tp_call, slot_tp_call, wrap_call), TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc,
"x.__cmp__(y) <==> cmp(x,y)"),
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
"x.__hash__() <==> hash(x)"),
TPSLOT("__call__", tp_call, slot_tp_call, wrap_call,
"x.__call__(...) <==> x(...)"),
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
wrap_binaryfunc), wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
TPSLOT("__getattribute__", tp_getattr, NULL, NULL), TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL), TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""),
TPSLOT("__getattr__", tp_getattr, NULL, NULL), TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr), TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr,
TPSLOT("__setattr__", tp_setattr, NULL, NULL), "x.__setattr__('name', value) <==> x.name = value"),
TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr), TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
TPSLOT("__delattr__", tp_setattr, NULL, NULL), TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr,
TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt), "x.__delattr__('name') <==> del x.name"),
TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le), TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq), TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt,
TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne), "x.__lt__(y) <==> x<y"),
TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt), TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le,
TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge), "x.__le__(y) <==> x<=y"),
TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc), TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq,
TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next), "x.__eq__(y) <==> x==y"),
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get), TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne,
TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set), "x.__ne__(y) <==> x!=y"),
TPSLOT("__init__", tp_init, slot_tp_init, wrap_init), TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt,
TPSLOT("__new__", tp_new, slot_tp_new, NULL), "x.__gt__(y) <==> x>y"),
TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge,
"x.__ge__(y) <==> x>=y"),
TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc,
"x.__iter__() <==> iter(x)"),
TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next,
"x.next() -> the next value, or raise StopIteration"),
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get,
"descr.__get__(obj[, type]) -> value"),
TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set,
"descr.__set__(obj, value)"),
TPSLOT("__init__", tp_init, slot_tp_init, wrap_init,
"x.__init__(...) initializes x; "
"see x.__class__.__doc__ for signature"),
TPSLOT("__new__", tp_new, slot_tp_new, NULL,
""),
{NULL} {NULL}
}; };
@ -3943,6 +3607,58 @@ fixup_slot_dispatchers(PyTypeObject *type)
} }
} }
/* This function is called by PyType_Ready() to populate the type's
dictionary with method descriptors for function slots. For each
function slot (like tp_repr) that's defined in the type, one or
more corresponding descriptors are added in the type's tp_dict
dictionary under the appropriate name (like __repr__). Some
function slots cause more than one descriptor to be added (for
example, the nb_add slot adds both __add__ and __radd__
descriptors) and some function slots compete for the same
descriptor (for example both sq_item and mp_subscript generate a
__getitem__ descriptor). This only adds new descriptors and
doesn't overwrite entries in tp_dict that were previously
defined. The descriptors contain a reference to the C function
they must call, so that it's safe if they are copied into a
subtype's __dict__ and the subtype has a different C function in
its slot -- calling the method defined by the descriptor will call
the C function that was used to create it, rather than the C
function present in the slot when it is called. (This is important
because a subtype may have a C function in the slot that calls the
method from the dictionary, and we want to avoid infinite recursion
here.) */
static int
add_operators(PyTypeObject *type)
{
PyObject *dict = type->tp_dict;
slotdef *p;
PyObject *descr;
void **ptr;
init_slotdefs();
for (p = slotdefs; p->name; p++) {
if (p->wrapper == NULL)
continue;
ptr = slotptr(type, p->offset);
if (!ptr || !*ptr)
continue;
if (PyDict_GetItem(dict, p->name_strobj))
continue;
descr = PyDescr_NewWrapper(type, p, *ptr);
if (descr == NULL)
return -1;
if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)
return -1;
Py_DECREF(descr);
}
if (type->tp_new != NULL) {
if (add_tp_new_wrapper(type) < 0)
return -1;
}
return 0;
}
/* Cooperative 'super' */ /* Cooperative 'super' */