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:
Thomas Wouters 2000-08-24 20:08:19 +00:00
parent 12bba852a9
commit e289e0bd0c
3 changed files with 647 additions and 29 deletions

View File

@ -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)
{ {

View File

@ -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 = {

View File

@ -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 = {