diff options
Diffstat (limited to 'Modules/_operator.c')
-rw-r--r-- | Modules/_operator.c | 285 |
1 files changed, 277 insertions, 8 deletions
diff --git a/Modules/_operator.c b/Modules/_operator.c index adeb99e..735affc 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -69,6 +69,7 @@ spami(truth , PyObject_IsTrue) spam2(op_add , PyNumber_Add) spam2(op_sub , PyNumber_Subtract) spam2(op_mul , PyNumber_Multiply) +spam2(op_matmul , PyNumber_MatrixMultiply) spam2(op_floordiv , PyNumber_FloorDivide) spam2(op_truediv , PyNumber_TrueDivide) spam2(op_mod , PyNumber_Remainder) @@ -86,6 +87,7 @@ spam2(op_or_ , PyNumber_Or) spam2(op_iadd , PyNumber_InPlaceAdd) spam2(op_isub , PyNumber_InPlaceSubtract) spam2(op_imul , PyNumber_InPlaceMultiply) +spam2(op_imatmul , PyNumber_InPlaceMatrixMultiply) spam2(op_ifloordiv , PyNumber_InPlaceFloorDivide) spam2(op_itruediv , PyNumber_InPlaceTrueDivide) spam2(op_imod , PyNumber_InPlaceRemainder) @@ -239,7 +241,7 @@ PyDoc_STRVAR(compare_digest__doc__, "Return 'a == b'. This function uses an approach designed to prevent\n" "timing analysis, making it appropriate for cryptography.\n" "a and b must both be of the same type: either str (ASCII only),\n" -"or any type that supports the buffer protocol (e.g. bytes).\n" +"or any bytes-like object.\n" "\n" "Note: If a and b are of different lengths, or if an error occurs,\n" "a timing attack could theoretically reveal information about the\n" @@ -343,6 +345,7 @@ spam2o(index, "index(a) -- Same as a.__index__()") spam2(add, "add(a, b) -- Same as a + b.") spam2(sub, "sub(a, b) -- Same as a - b.") spam2(mul, "mul(a, b) -- Same as a * b.") +spam2(matmul, "matmul(a, b) -- Same as a @ b.") spam2(floordiv, "floordiv(a, b) -- Same as a // b.") spam2(truediv, "truediv(a, b) -- Same as a / b.") spam2(mod, "mod(a, b) -- Same as a % b.") @@ -360,6 +363,7 @@ spam2(or_, "or_(a, b) -- Same as a | b.") spam2(iadd, "a = iadd(a, b) -- Same as a += b.") spam2(isub, "a = isub(a, b) -- Same as a -= b.") spam2(imul, "a = imul(a, b) -- Same as a *= b.") +spam2(imatmul, "a = imatmul(a, b) -- Same as a @= b.") spam2(ifloordiv, "a = ifloordiv(a, b) -- Same as a //= b.") spam2(itruediv, "a = itruediv(a, b) -- Same as a /= b") spam2(imod, "a = imod(a, b) -- Same as a %= b.") @@ -481,6 +485,41 @@ itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw) return result; } +static PyObject * +itemgetter_repr(itemgetterobject *ig) +{ + PyObject *repr; + const char *reprfmt; + + int status = Py_ReprEnter((PyObject *)ig); + if (status != 0) { + if (status < 0) + return NULL; + return PyUnicode_FromFormat("%s(...)", Py_TYPE(ig)->tp_name); + } + + reprfmt = ig->nitems == 1 ? "%s(%R)" : "%s%R"; + repr = PyUnicode_FromFormat(reprfmt, Py_TYPE(ig)->tp_name, ig->item); + Py_ReprLeave((PyObject *)ig); + return repr; +} + +static PyObject * +itemgetter_reduce(itemgetterobject *ig) +{ + if (ig->nitems == 1) + return Py_BuildValue("O(O)", Py_TYPE(ig), ig->item); + return PyTuple_Pack(2, Py_TYPE(ig), ig->item); +} + +PyDoc_STRVAR(reduce_doc, "Return state information for pickling"); + +static PyMethodDef itemgetter_methods[] = { + {"__reduce__", (PyCFunction)itemgetter_reduce, METH_NOARGS, + reduce_doc}, + {NULL} +}; + PyDoc_STRVAR(itemgetter_doc, "itemgetter(item, ...) --> itemgetter object\n\ \n\ @@ -499,7 +538,7 @@ static PyTypeObject itemgetter_type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - 0, /* tp_repr */ + (reprfunc)itemgetter_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -517,7 +556,7 @@ static PyTypeObject itemgetter_type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + itemgetter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ @@ -733,6 +772,93 @@ attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw) return result; } +static PyObject * +dotjoinattr(PyObject *attr, PyObject **attrsep) +{ + if (PyTuple_CheckExact(attr)) { + if (*attrsep == NULL) { + *attrsep = PyUnicode_FromString("."); + if (*attrsep == NULL) + return NULL; + } + return PyUnicode_Join(*attrsep, attr); + } else { + Py_INCREF(attr); + return attr; + } +} + +static PyObject * +attrgetter_args(attrgetterobject *ag) +{ + Py_ssize_t i; + PyObject *attrsep = NULL; + PyObject *attrstrings = PyTuple_New(ag->nattrs); + if (attrstrings == NULL) + return NULL; + + for (i = 0; i < ag->nattrs; ++i) { + PyObject *attr = PyTuple_GET_ITEM(ag->attr, i); + PyObject *attrstr = dotjoinattr(attr, &attrsep); + if (attrstr == NULL) { + Py_XDECREF(attrsep); + Py_DECREF(attrstrings); + return NULL; + } + PyTuple_SET_ITEM(attrstrings, i, attrstr); + } + Py_XDECREF(attrsep); + return attrstrings; +} + +static PyObject * +attrgetter_repr(attrgetterobject *ag) +{ + PyObject *repr = NULL; + int status = Py_ReprEnter((PyObject *)ag); + if (status != 0) { + if (status < 0) + return NULL; + return PyUnicode_FromFormat("%s(...)", Py_TYPE(ag)->tp_name); + } + + if (ag->nattrs == 1) { + PyObject *attrsep = NULL; + PyObject *attr = dotjoinattr(PyTuple_GET_ITEM(ag->attr, 0), &attrsep); + if (attr != NULL) { + repr = PyUnicode_FromFormat("%s(%R)", Py_TYPE(ag)->tp_name, attr); + Py_DECREF(attr); + } + Py_XDECREF(attrsep); + } + else { + PyObject *attrstrings = attrgetter_args(ag); + if (attrstrings != NULL) { + repr = PyUnicode_FromFormat("%s%R", + Py_TYPE(ag)->tp_name, attrstrings); + Py_DECREF(attrstrings); + } + } + Py_ReprLeave((PyObject *)ag); + return repr; +} + +static PyObject * +attrgetter_reduce(attrgetterobject *ag) +{ + PyObject *attrstrings = attrgetter_args(ag); + if (attrstrings == NULL) + return NULL; + + return Py_BuildValue("ON", Py_TYPE(ag), attrstrings); +} + +static PyMethodDef attrgetter_methods[] = { + {"__reduce__", (PyCFunction)attrgetter_reduce, METH_NOARGS, + reduce_doc}, + {NULL} +}; + PyDoc_STRVAR(attrgetter_doc, "attrgetter(attr, ...) --> attrgetter object\n\ \n\ @@ -753,7 +879,7 @@ static PyTypeObject attrgetter_type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - 0, /* tp_repr */ + (reprfunc)attrgetter_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -771,7 +897,7 @@ static PyTypeObject attrgetter_type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + attrgetter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ @@ -809,6 +935,13 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } + name = PyTuple_GET_ITEM(args, 0); + if (!PyUnicode_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "method name must be a string"); + return NULL; + } + /* create methodcallerobject structure */ mc = PyObject_GC_New(methodcallerobject, &methodcaller_type); if (mc == NULL) @@ -821,8 +954,8 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } mc->args = newargs; - name = PyTuple_GET_ITEM(args, 0); Py_INCREF(name); + PyUnicode_InternInPlace(&name); mc->name = name; Py_XINCREF(kwds); @@ -865,6 +998,142 @@ methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw) return result; } +static PyObject * +methodcaller_repr(methodcallerobject *mc) +{ + PyObject *argreprs, *repr = NULL, *sep, *joinedargreprs; + Py_ssize_t numtotalargs, numposargs, numkwdargs, i; + int status = Py_ReprEnter((PyObject *)mc); + if (status != 0) { + if (status < 0) + return NULL; + return PyUnicode_FromFormat("%s(...)", Py_TYPE(mc)->tp_name); + } + + if (mc->kwds != NULL) { + numkwdargs = PyDict_Size(mc->kwds); + if (numkwdargs < 0) { + Py_ReprLeave((PyObject *)mc); + return NULL; + } + } else { + numkwdargs = 0; + } + + numposargs = PyTuple_GET_SIZE(mc->args); + numtotalargs = numposargs + numkwdargs; + + if (numtotalargs == 0) { + repr = PyUnicode_FromFormat("%s(%R)", Py_TYPE(mc)->tp_name, mc->name); + Py_ReprLeave((PyObject *)mc); + return repr; + } + + argreprs = PyTuple_New(numtotalargs); + if (argreprs == NULL) { + Py_ReprLeave((PyObject *)mc); + return NULL; + } + + for (i = 0; i < numposargs; ++i) { + PyObject *onerepr = PyObject_Repr(PyTuple_GET_ITEM(mc->args, i)); + if (onerepr == NULL) + goto done; + PyTuple_SET_ITEM(argreprs, i, onerepr); + } + + if (numkwdargs != 0) { + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(mc->kwds, &pos, &key, &value)) { + PyObject *onerepr = PyUnicode_FromFormat("%U=%R", key, value); + if (onerepr == NULL) + goto done; + if (i >= numtotalargs) { + i = -1; + break; + } + PyTuple_SET_ITEM(argreprs, i, onerepr); + ++i; + } + if (i != numtotalargs) { + PyErr_SetString(PyExc_RuntimeError, + "keywords dict changed size during iteration"); + goto done; + } + } + + sep = PyUnicode_FromString(", "); + if (sep == NULL) + goto done; + + joinedargreprs = PyUnicode_Join(sep, argreprs); + Py_DECREF(sep); + if (joinedargreprs == NULL) + goto done; + + repr = PyUnicode_FromFormat("%s(%R, %U)", Py_TYPE(mc)->tp_name, + mc->name, joinedargreprs); + Py_DECREF(joinedargreprs); + +done: + Py_DECREF(argreprs); + Py_ReprLeave((PyObject *)mc); + return repr; +} + +static PyObject * +methodcaller_reduce(methodcallerobject *mc) +{ + PyObject *newargs; + if (!mc->kwds || PyDict_Size(mc->kwds) == 0) { + Py_ssize_t i; + Py_ssize_t callargcount = PyTuple_GET_SIZE(mc->args); + newargs = PyTuple_New(1 + callargcount); + if (newargs == NULL) + return NULL; + Py_INCREF(mc->name); + PyTuple_SET_ITEM(newargs, 0, mc->name); + for (i = 0; i < callargcount; ++i) { + PyObject *arg = PyTuple_GET_ITEM(mc->args, i); + Py_INCREF(arg); + PyTuple_SET_ITEM(newargs, i + 1, arg); + } + return Py_BuildValue("ON", Py_TYPE(mc), newargs); + } + else { + PyObject *functools; + PyObject *partial; + PyObject *constructor; + _Py_IDENTIFIER(partial); + functools = PyImport_ImportModule("functools"); + if (!functools) + return NULL; + partial = _PyObject_GetAttrId(functools, &PyId_partial); + Py_DECREF(functools); + if (!partial) + return NULL; + newargs = PyTuple_New(2); + if (newargs == NULL) { + Py_DECREF(partial); + return NULL; + } + Py_INCREF(Py_TYPE(mc)); + PyTuple_SET_ITEM(newargs, 0, (PyObject *)Py_TYPE(mc)); + Py_INCREF(mc->name); + PyTuple_SET_ITEM(newargs, 1, mc->name); + constructor = PyObject_Call(partial, newargs, mc->kwds); + Py_DECREF(newargs); + Py_DECREF(partial); + return Py_BuildValue("NO", constructor, mc->args); + } +} + +static PyMethodDef methodcaller_methods[] = { + {"__reduce__", (PyCFunction)methodcaller_reduce, METH_NOARGS, + reduce_doc}, + {NULL} +}; PyDoc_STRVAR(methodcaller_doc, "methodcaller(name, ...) --> methodcaller object\n\ \n\ @@ -884,7 +1153,7 @@ static PyTypeObject methodcaller_type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - 0, /* tp_repr */ + (reprfunc)methodcaller_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -902,7 +1171,7 @@ static PyTypeObject methodcaller_type = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + methodcaller_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ |