mirror of https://github.com/python/cpython
Support for the in-place operations introduced by augmented assignment. Only
the list object supports this currently, but other candidates are gladly accepted (like arraymodule and such.)
This commit is contained in:
parent
12bba852a9
commit
e289e0bd0c
|
@ -614,6 +614,486 @@ PyNumber_Power(PyObject *v, PyObject *w, PyObject *z)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Binary in-place operators */
|
||||||
|
|
||||||
|
/* The in-place operators are defined to fall back to the 'normal',
|
||||||
|
non in-place operations, if the in-place methods are not in place, and to
|
||||||
|
take class instances into account. This is how it is supposed to work:
|
||||||
|
|
||||||
|
- If the left-hand-side object (the first argument) is an
|
||||||
|
instance object, try to let PyInstance_HalfBinOp() handle it. Pass the
|
||||||
|
non in-place variant of the function as callback, because it will only
|
||||||
|
be used if the left-hand object is changed by coercion.
|
||||||
|
|
||||||
|
- Otherwise, if the left hand object is not an instance object, it has
|
||||||
|
the appropriate struct members, and they are filled, call the
|
||||||
|
appropriate function and return the result. No coercion is done on the
|
||||||
|
arguments; the left-hand object is the one the operation is performed
|
||||||
|
on, and it's up to the function to deal with the right-hand object.
|
||||||
|
|
||||||
|
- Otherwise, in-place modification is not supported. Handle it exactly as
|
||||||
|
a non in-place operation of the same kind:
|
||||||
|
|
||||||
|
- If either object is an instance, let PyInstance_DoBinOp() handle it.
|
||||||
|
|
||||||
|
- Otherwise, both arguments are C types. If the left-hand object has
|
||||||
|
the appropriate struct members filled, coerce, call the
|
||||||
|
appropriate function, and return the result.
|
||||||
|
|
||||||
|
- Otherwise, we are out of options: raise a type error specific to
|
||||||
|
augmented assignment.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HASINPLACE(t) PyType_HasFeature((t)->ob_type, Py_TPFLAGS_HAVE_INPLACEOPS)
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceOr(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__ior__", &x, PyNumber_Or,
|
||||||
|
0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_or) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__or__", "__ror__", PyNumber_Or);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_or) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for |=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceXor(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__ixor__", &x, PyNumber_Xor,
|
||||||
|
0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_xor) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__xor__", "__rxor__", PyNumber_Xor);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_xor) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for ^=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceAnd(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__iand__", &x, PyNumber_And,
|
||||||
|
0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_and) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__and__", "__rand__", PyNumber_And);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_and) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for &=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceLshift(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__ilshift__", &x,
|
||||||
|
PyNumber_Lshift, 0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_lshift) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__lshift__", "__rlshift__", PyNumber_Lshift);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_lshift) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for <<=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceRshift(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__irshift__", &x,
|
||||||
|
PyNumber_Rshift, 0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_rshift) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__rshift__", "__rrshift__", PyNumber_Rshift);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_rshift) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for >>=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__iadd__", &x,
|
||||||
|
PyNumber_Add, 0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (HASINPLACE(v) && (v->ob_type->tp_as_sequence != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_sequence->sq_inplace_concat) != NULL) ||
|
||||||
|
(v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_add) != NULL))
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__add__", "__radd__", PyNumber_Add);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_sequence != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_sequence->sq_concat) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
else if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_add) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for +=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceSubtract(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__isub__", &x,
|
||||||
|
PyNumber_Subtract, 0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_subtract) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__sub__", "__rsub__", PyNumber_Subtract);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_subtract) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for -=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceMultiply(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject * (*f2)(PyObject *, int) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__imul__", &x,
|
||||||
|
PyNumber_Multiply, 0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_multiply) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
else if (v->ob_type->tp_as_sequence != NULL && HASINPLACE(v) &&
|
||||||
|
(f2 = v->ob_type->tp_as_sequence->sq_inplace_repeat) != NULL) {
|
||||||
|
long mul_value;
|
||||||
|
|
||||||
|
if (PyInt_Check(w)) {
|
||||||
|
mul_value = PyInt_AsLong(w);
|
||||||
|
}
|
||||||
|
else if (PyLong_Check(w)) {
|
||||||
|
mul_value = PyLong_AsLong(w);
|
||||||
|
if (mul_value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return type_error(
|
||||||
|
"can't multiply sequence with non-int");
|
||||||
|
}
|
||||||
|
return (*f2)(v, (int)mul_value);
|
||||||
|
}
|
||||||
|
BINOP(v, w, "__mul__", "__rmul__", PyNumber_Multiply);
|
||||||
|
|
||||||
|
/* if (tp->tp_as_number != NULL &&
|
||||||
|
w->ob_type->tp_as_sequence != NULL) { */
|
||||||
|
/* number*sequence -- swap v and w */
|
||||||
|
/* PyObject *tmp = v;
|
||||||
|
v = w;
|
||||||
|
w = tmp;
|
||||||
|
tp = v->ob_type;
|
||||||
|
} */
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_multiply) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_sequence != NULL &&
|
||||||
|
(f2 = v->ob_type->tp_as_sequence->sq_repeat) != NULL) {
|
||||||
|
long mul_value;
|
||||||
|
|
||||||
|
if (PyInt_Check(w)) {
|
||||||
|
mul_value = PyInt_AsLong(w);
|
||||||
|
}
|
||||||
|
else if (PyLong_Check(w)) {
|
||||||
|
mul_value = PyLong_AsLong(w);
|
||||||
|
if (mul_value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return type_error(
|
||||||
|
"can't multiply sequence with non-int");
|
||||||
|
}
|
||||||
|
return (*f2)(v, (int)mul_value);
|
||||||
|
}
|
||||||
|
return type_error("bad operand type(s) for *=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceDivide(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__idiv__", &x,
|
||||||
|
PyNumber_Divide, 0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_divide) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__div__", "__rdiv__", PyNumber_Divide);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if (v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_divide) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for /=");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlaceRemainder(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__imod__", &x,
|
||||||
|
PyNumber_Remainder, 0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_remainder) != NULL)
|
||||||
|
return (*f)(v, w);
|
||||||
|
|
||||||
|
if (PyString_Check(v))
|
||||||
|
return PyString_Format(v, w);
|
||||||
|
else if (PyUnicode_Check(v))
|
||||||
|
return PyUnicode_Format(v, w);
|
||||||
|
|
||||||
|
BINOP(v, w, "__mod__", "__rmod__", PyNumber_Remainder);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number != NULL) {
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if ((f = v->ob_type->tp_as_number->nb_remainder) != NULL)
|
||||||
|
x = (*f)(v, w);
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
if (f != NULL)
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_error("bad operand type(s) for %=");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* In-place Power (binary or ternary, for API consistency) */
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
do_inplace_pow(PyObject *v, PyObject *w)
|
||||||
|
{
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *, PyObject *) = NULL;
|
||||||
|
PyObject *x;
|
||||||
|
|
||||||
|
if (PyInstance_Check(v)) {
|
||||||
|
if (PyInstance_HalfBinOp(v, w, "__ipow__", &x, do_pow, 0) <= 0)
|
||||||
|
return x;
|
||||||
|
} else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
|
||||||
|
(f = v->ob_type->tp_as_number->nb_inplace_power) != NULL)
|
||||||
|
return (*f)(v, w, Py_None);
|
||||||
|
|
||||||
|
BINOP(v, w, "__pow__", "__rpow__", do_pow);
|
||||||
|
|
||||||
|
if (v->ob_type->tp_as_number == NULL ||
|
||||||
|
w->ob_type->tp_as_number == NULL) {
|
||||||
|
return type_error("bad operand type(s) for **=");
|
||||||
|
}
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
return NULL;
|
||||||
|
if ((f = v->ob_type->tp_as_number->nb_power) != NULL)
|
||||||
|
x = (*f)(v, w, Py_None);
|
||||||
|
else
|
||||||
|
x = type_error("bad operand type(s) for **=");
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z)
|
||||||
|
{
|
||||||
|
PyObject *res;
|
||||||
|
PyObject *v1, *z1, *w2, *z2, *oldv;
|
||||||
|
PyObject * (*f)(PyObject *, PyObject *, PyObject *);
|
||||||
|
|
||||||
|
if (z == Py_None)
|
||||||
|
return do_inplace_pow(v, w);
|
||||||
|
/* XXX The ternary version doesn't do class instance coercions */
|
||||||
|
if (PyInstance_Check(v))
|
||||||
|
return v->ob_type->tp_as_number->nb_inplace_power(v, w, z);
|
||||||
|
if (v->ob_type->tp_as_number == NULL ||
|
||||||
|
z->ob_type->tp_as_number == NULL ||
|
||||||
|
w->ob_type->tp_as_number == NULL) {
|
||||||
|
return type_error("(inplace) pow(x, y, z) requires numeric arguments");
|
||||||
|
}
|
||||||
|
oldv = v;
|
||||||
|
Py_INCREF(oldv);
|
||||||
|
res = NULL;
|
||||||
|
if (PyNumber_Coerce(&v, &w) != 0)
|
||||||
|
goto error3;
|
||||||
|
v1 = v;
|
||||||
|
z1 = z;
|
||||||
|
if (PyNumber_Coerce(&v1, &z1) != 0)
|
||||||
|
goto error2;
|
||||||
|
w2 = w;
|
||||||
|
z2 = z1;
|
||||||
|
if (PyNumber_Coerce(&w2, &z2) != 0)
|
||||||
|
goto error1;
|
||||||
|
if (oldv == v1 && HASINPLACE(v1) && v->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v1->ob_type->tp_as_number->nb_inplace_power) != NULL)
|
||||||
|
res = (*f)(v1, w2, z2);
|
||||||
|
else if (v1->ob_type->tp_as_number != NULL &&
|
||||||
|
(f = v1->ob_type->tp_as_number->nb_power) != NULL)
|
||||||
|
res = (*f)(v1, w2, z2);
|
||||||
|
else
|
||||||
|
res = type_error(
|
||||||
|
"(inplace) pow(x, y, z) not defined for these operands");
|
||||||
|
Py_DECREF(w2);
|
||||||
|
Py_DECREF(z2);
|
||||||
|
error1:
|
||||||
|
Py_DECREF(v1);
|
||||||
|
Py_DECREF(z1);
|
||||||
|
error2:
|
||||||
|
Py_DECREF(v);
|
||||||
|
Py_DECREF(w);
|
||||||
|
error3:
|
||||||
|
Py_DECREF(oldv);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Unary operators and functions */
|
/* Unary operators and functions */
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -856,6 +1336,40 @@ PySequence_Repeat(PyObject *o, int count)
|
||||||
return type_error("object can't be repeated");
|
return type_error("object can't be repeated");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PySequence_InPlaceConcat(PyObject *s, PyObject *o)
|
||||||
|
{
|
||||||
|
PySequenceMethods *m;
|
||||||
|
|
||||||
|
if (s == NULL || o == NULL)
|
||||||
|
return null_error();
|
||||||
|
|
||||||
|
m = s->ob_type->tp_as_sequence;
|
||||||
|
if (m && HASINPLACE(s) && m->sq_inplace_concat)
|
||||||
|
return m->sq_inplace_concat(s, o);
|
||||||
|
if (m && m->sq_concat)
|
||||||
|
return m->sq_concat(s, o);
|
||||||
|
|
||||||
|
return type_error("object can't be concatenated");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PySequence_InPlaceRepeat(PyObject *o, int count)
|
||||||
|
{
|
||||||
|
PySequenceMethods *m;
|
||||||
|
|
||||||
|
if (o == NULL)
|
||||||
|
return null_error();
|
||||||
|
|
||||||
|
m = o->ob_type->tp_as_sequence;
|
||||||
|
if (m && HASINPLACE(o) && m->sq_inplace_repeat)
|
||||||
|
return m->sq_inplace_repeat(o, count);
|
||||||
|
if (m && m->sq_repeat)
|
||||||
|
return m->sq_repeat(o, count);
|
||||||
|
|
||||||
|
return type_error("object can't be repeated");
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PySequence_GetItem(PyObject *s, int i)
|
PySequence_GetItem(PyObject *s, int i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1193,12 +1193,6 @@ generic_unary_op(PyInstanceObject *self, PyObject *methodname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Forward */
|
|
||||||
static int
|
|
||||||
halfbinop(PyObject *, PyObject *, char *, PyObject **,
|
|
||||||
PyObject * (*)(PyObject *, PyObject *), int);
|
|
||||||
|
|
||||||
|
|
||||||
/* Implement a binary operator involving at least one class instance. */
|
/* Implement a binary operator involving at least one class instance. */
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -1208,9 +1202,9 @@ PyInstance_DoBinOp(PyObject *v, PyObject *w, char *opname, char *ropname,
|
||||||
char buf[256];
|
char buf[256];
|
||||||
PyObject *result = NULL;
|
PyObject *result = NULL;
|
||||||
|
|
||||||
if (halfbinop(v, w, opname, &result, thisfunc, 0) <= 0)
|
if (PyInstance_HalfBinOp(v, w, opname, &result, thisfunc, 0) <= 0)
|
||||||
return result;
|
return result;
|
||||||
if (halfbinop(w, v, ropname, &result, thisfunc, 1) <= 0)
|
if (PyInstance_HalfBinOp(w, v, ropname, &result, thisfunc, 1) <= 0)
|
||||||
return result;
|
return result;
|
||||||
/* Sigh -- special case for comparisons */
|
/* Sigh -- special case for comparisons */
|
||||||
if (strcmp(opname, "__cmp__") == 0) {
|
if (strcmp(opname, "__cmp__") == 0) {
|
||||||
|
@ -1234,9 +1228,9 @@ PyInstance_DoBinOp(PyObject *v, PyObject *w, char *opname, char *ropname,
|
||||||
|
|
||||||
static PyObject *coerce_obj;
|
static PyObject *coerce_obj;
|
||||||
|
|
||||||
static int
|
int
|
||||||
halfbinop(PyObject *v, PyObject *w, char *opname, PyObject **r_result,
|
PyInstance_HalfBinOp(PyObject *v, PyObject *w, char *opname, PyObject **r_result,
|
||||||
PyObject * (*thisfunc)(PyObject *, PyObject *), int swapped)
|
PyObject * (*thisfunc)(PyObject *, PyObject *), int swapped)
|
||||||
{
|
{
|
||||||
PyObject *func;
|
PyObject *func;
|
||||||
PyObject *args;
|
PyObject *args;
|
||||||
|
@ -1451,6 +1445,35 @@ instance_pow(PyObject *v, PyObject *w, PyObject *z)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
instance_inplace_pow(PyObject *v, PyObject *w, PyObject *z)
|
||||||
|
{
|
||||||
|
/* XXX Doesn't do coercions... */
|
||||||
|
PyObject *func;
|
||||||
|
PyObject *args;
|
||||||
|
PyObject *result;
|
||||||
|
static PyObject *ipowstr;
|
||||||
|
|
||||||
|
if (ipowstr == NULL)
|
||||||
|
ipowstr = PyString_InternFromString("__ipow__");
|
||||||
|
func = PyObject_GetAttr(v, ipowstr);
|
||||||
|
if (func == NULL) {
|
||||||
|
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||||
|
return NULL;
|
||||||
|
return instance_pow(v, w, z);
|
||||||
|
}
|
||||||
|
args = Py_BuildValue("(OO)", w, z);
|
||||||
|
if (args == NULL) {
|
||||||
|
Py_DECREF(func);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
result = PyEval_CallObject(func, args);
|
||||||
|
Py_DECREF(func);
|
||||||
|
Py_DECREF(args);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyNumberMethods instance_as_number = {
|
static PyNumberMethods instance_as_number = {
|
||||||
0, /*nb_add*/
|
0, /*nb_add*/
|
||||||
0, /*nb_subtract*/
|
0, /*nb_subtract*/
|
||||||
|
@ -1475,6 +1498,17 @@ static PyNumberMethods instance_as_number = {
|
||||||
(unaryfunc)instance_float, /*nb_float*/
|
(unaryfunc)instance_float, /*nb_float*/
|
||||||
(unaryfunc)instance_oct, /*nb_oct*/
|
(unaryfunc)instance_oct, /*nb_oct*/
|
||||||
(unaryfunc)instance_hex, /*nb_hex*/
|
(unaryfunc)instance_hex, /*nb_hex*/
|
||||||
|
0, /*nb_inplace_add*/
|
||||||
|
0, /*nb_inplace_subtract*/
|
||||||
|
0, /*nb_inplace_multiply*/
|
||||||
|
0, /*nb_inplace_divide*/
|
||||||
|
0, /*nb_inplace_remainder*/
|
||||||
|
(ternaryfunc)instance_inplace_pow, /*nb_inplace_power*/
|
||||||
|
0, /*nb_inplace_lshift*/
|
||||||
|
0, /*nb_inplace_rshift*/
|
||||||
|
0, /*nb_inplace_and*/
|
||||||
|
0, /*nb_inplace_xor*/
|
||||||
|
0, /*nb_inplace_or*/
|
||||||
};
|
};
|
||||||
|
|
||||||
PyTypeObject PyInstance_Type = {
|
PyTypeObject PyInstance_Type = {
|
||||||
|
|
|
@ -496,6 +496,50 @@ PyList_SetSlice(PyObject *a, int ilow, int ihigh, PyObject *v)
|
||||||
return list_ass_slice((PyListObject *)a, ilow, ihigh, v);
|
return list_ass_slice((PyListObject *)a, ilow, ihigh, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
list_inplace_repeat(PyListObject *self, int n)
|
||||||
|
{
|
||||||
|
PyObject **items;
|
||||||
|
int size, i, j;
|
||||||
|
|
||||||
|
|
||||||
|
size = PyList_GET_SIZE(self);
|
||||||
|
if (size == 0) {
|
||||||
|
Py_INCREF(self);
|
||||||
|
return (PyObject *)self;
|
||||||
|
}
|
||||||
|
|
||||||
|
items = self->ob_item;
|
||||||
|
|
||||||
|
if (n < 1) {
|
||||||
|
self->ob_item = NULL;
|
||||||
|
self->ob_size = 0;
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
Py_XDECREF(items[i]);
|
||||||
|
PyMem_DEL(items);
|
||||||
|
Py_INCREF(self);
|
||||||
|
return (PyObject *)self;
|
||||||
|
}
|
||||||
|
|
||||||
|
NRESIZE(items, PyObject*, size*n);
|
||||||
|
if (items == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
self->ob_item = items;
|
||||||
|
for (i = 1; i < n; i++) { /* Start counting at 1, not 0 */
|
||||||
|
for (j = 0; j < size; j++) {
|
||||||
|
PyObject *o = PyList_GET_ITEM(self, j);
|
||||||
|
Py_INCREF(o);
|
||||||
|
PyList_SET_ITEM(self, self->ob_size++, o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_INCREF(self);
|
||||||
|
return (PyObject *)self;
|
||||||
|
finally:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
list_ass_item(PyListObject *a, int i, PyObject *v)
|
list_ass_item(PyListObject *a, int i, PyObject *v)
|
||||||
{
|
{
|
||||||
|
@ -556,25 +600,17 @@ listappend(PyListObject *self, PyObject *args)
|
||||||
return ins(self, (int) self->ob_size, v);
|
return ins(self, (int) self->ob_size, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static int
|
||||||
listextend(PyListObject *self, PyObject *args)
|
listextend_internal(PyListObject *self, PyObject *b)
|
||||||
{
|
{
|
||||||
PyObject *b = NULL, *res = NULL;
|
|
||||||
PyObject **items;
|
PyObject **items;
|
||||||
int selflen = PyList_GET_SIZE(self);
|
int selflen = PyList_GET_SIZE(self);
|
||||||
int blen;
|
int blen;
|
||||||
register int i;
|
register int i;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O:extend", &b))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
b = PySequence_Fast(b, "list.extend() argument must be a sequence");
|
|
||||||
if (!b)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (PyObject_Size(b) == 0)
|
if (PyObject_Size(b) == 0)
|
||||||
/* short circuit when b is empty */
|
/* short circuit when b is empty */
|
||||||
goto ok;
|
return 0;
|
||||||
|
|
||||||
if (self == (PyListObject*)b) {
|
if (self == (PyListObject*)b) {
|
||||||
/* as in list_ass_slice() we must special case the
|
/* as in list_ass_slice() we must special case the
|
||||||
|
@ -586,7 +622,7 @@ listextend(PyListObject *self, PyObject *args)
|
||||||
Py_DECREF(b);
|
Py_DECREF(b);
|
||||||
b = PyList_New(selflen);
|
b = PyList_New(selflen);
|
||||||
if (!b)
|
if (!b)
|
||||||
return NULL;
|
return -1;
|
||||||
for (i = 0; i < selflen; i++) {
|
for (i = 0; i < selflen; i++) {
|
||||||
PyObject *o = PyList_GET_ITEM(self, i);
|
PyObject *o = PyList_GET_ITEM(self, i);
|
||||||
Py_INCREF(o);
|
Py_INCREF(o);
|
||||||
|
@ -601,8 +637,10 @@ listextend(PyListObject *self, PyObject *args)
|
||||||
NRESIZE(items, PyObject*, selflen + blen);
|
NRESIZE(items, PyObject*, selflen + blen);
|
||||||
if (items == NULL) {
|
if (items == NULL) {
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
goto failed;
|
Py_DECREF(b);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->ob_item = items;
|
self->ob_item = items;
|
||||||
|
|
||||||
/* populate the end of self with b's items */
|
/* populate the end of self with b's items */
|
||||||
|
@ -611,15 +649,45 @@ listextend(PyListObject *self, PyObject *args)
|
||||||
Py_INCREF(o);
|
Py_INCREF(o);
|
||||||
PyList_SET_ITEM(self, self->ob_size++, o);
|
PyList_SET_ITEM(self, self->ob_size++, o);
|
||||||
}
|
}
|
||||||
ok:
|
|
||||||
res = Py_None;
|
|
||||||
Py_INCREF(res);
|
|
||||||
failed:
|
|
||||||
Py_DECREF(b);
|
Py_DECREF(b);
|
||||||
return res;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
list_inplace_concat(PyListObject *self, PyObject *other)
|
||||||
|
{
|
||||||
|
other = PySequence_Fast(other, "argument to += must be a sequence");
|
||||||
|
if (!other)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (listextend_internal(self, other) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_INCREF(self);
|
||||||
|
return (PyObject *)self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
listextend(PyListObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
|
||||||
|
PyObject *b;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O:extend", &b))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
b = PySequence_Fast(b, "list.extend() argument must be a sequence");
|
||||||
|
if (!b)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (listextend_internal(self, b) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
listpop(PyListObject *self, PyObject *args)
|
listpop(PyListObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -1407,6 +1475,8 @@ static PySequenceMethods list_as_sequence = {
|
||||||
(intobjargproc)list_ass_item, /*sq_ass_item*/
|
(intobjargproc)list_ass_item, /*sq_ass_item*/
|
||||||
(intintobjargproc)list_ass_slice, /*sq_ass_slice*/
|
(intintobjargproc)list_ass_slice, /*sq_ass_slice*/
|
||||||
(objobjproc)list_contains, /*sq_contains*/
|
(objobjproc)list_contains, /*sq_contains*/
|
||||||
|
(binaryfunc)list_inplace_concat, /*sq_inplace_concat*/
|
||||||
|
(intargfunc)list_inplace_repeat, /*sq_inplace_repeat*/
|
||||||
};
|
};
|
||||||
|
|
||||||
PyTypeObject PyList_Type = {
|
PyTypeObject PyList_Type = {
|
||||||
|
|
Loading…
Reference in New Issue