#include "Python.h"
#include "pycore_moduleobject.h"
#include "structmember.h"
#include "pycore_runtime.h"
#include "clinic/_operator.c.h"
typedef struct {
PyObject *itemgetter_type;
PyObject *attrgetter_type;
PyObject *methodcaller_type;
} _operator_state;
static inline _operator_state*
get_operator_state(PyObject *module)
{
void *state = _PyModule_GetState(module);
assert(state != NULL);
return (_operator_state *)state;
}
PyDoc_STRVAR(operator_doc,
"Operator interface.\n\
\n\
This module exports a set of functions implemented in C corresponding\n\
to the intrinsic operators of Python. For example, operator.add(x, y)\n\
is equivalent to the expression x+y. The function names are those\n\
used for special methods; variants without leading and trailing\n\
'__' are also provided for convenience.");
static int
_operator_truth_impl(PyObject *module, PyObject *a)
{
return PyObject_IsTrue(a);
}
static PyObject *
_operator_add_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Add(a, b);
}
static PyObject *
_operator_sub_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Subtract(a, b);
}
static PyObject *
_operator_mul_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Multiply(a, b);
}
static PyObject *
_operator_matmul_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_MatrixMultiply(a, b);
}
static PyObject *
_operator_floordiv_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_FloorDivide(a, b);
}
static PyObject *
_operator_truediv_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_TrueDivide(a, b);
}
static PyObject *
_operator_mod_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Remainder(a, b);
}
static PyObject *
_operator_neg(PyObject *module, PyObject *a)
{
return PyNumber_Negative(a);
}
static PyObject *
_operator_pos(PyObject *module, PyObject *a)
{
return PyNumber_Positive(a);
}
static PyObject *
_operator_abs(PyObject *module, PyObject *a)
{
return PyNumber_Absolute(a);
}
static PyObject *
_operator_inv(PyObject *module, PyObject *a)
{
return PyNumber_Invert(a);
}
static PyObject *
_operator_invert(PyObject *module, PyObject *a)
{
return PyNumber_Invert(a);
}
static PyObject *
_operator_lshift_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Lshift(a, b);
}
static PyObject *
_operator_rshift_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Rshift(a, b);
}
static int
_operator_not__impl(PyObject *module, PyObject *a)
{
return PyObject_Not(a);
}
static PyObject *
_operator_and__impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_And(a, b);
}
static PyObject *
_operator_xor_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Xor(a, b);
}
static PyObject *
_operator_or__impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Or(a, b);
}
static PyObject *
_operator_iadd_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceAdd(a, b);
}
static PyObject *
_operator_isub_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceSubtract(a, b);
}
static PyObject *
_operator_imul_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceMultiply(a, b);
}
static PyObject *
_operator_imatmul_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceMatrixMultiply(a, b);
}
static PyObject *
_operator_ifloordiv_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceFloorDivide(a, b);
}
static PyObject *
_operator_itruediv_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceTrueDivide(a, b);
}
static PyObject *
_operator_imod_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceRemainder(a, b);
}
static PyObject *
_operator_ilshift_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceLshift(a, b);
}
static PyObject *
_operator_irshift_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceRshift(a, b);
}
static PyObject *
_operator_iand_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceAnd(a, b);
}
static PyObject *
_operator_ixor_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceXor(a, b);
}
static PyObject *
_operator_ior_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlaceOr(a, b);
}
static PyObject *
_operator_concat_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PySequence_Concat(a, b);
}
static PyObject *
_operator_iconcat_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PySequence_InPlaceConcat(a, b);
}
static int
_operator_contains_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PySequence_Contains(a, b);
}
static Py_ssize_t
_operator_indexOf_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PySequence_Index(a, b);
}
static Py_ssize_t
_operator_countOf_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PySequence_Count(a, b);
}
static PyObject *
_operator_getitem_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyObject_GetItem(a, b);
}
static PyObject *
_operator_setitem_impl(PyObject *module, PyObject *a, PyObject *b,
PyObject *c)
{
if (-1 == PyObject_SetItem(a, b, c))
return NULL;
Py_RETURN_NONE;
}
static PyObject *
_operator_delitem_impl(PyObject *module, PyObject *a, PyObject *b)
{
if (-1 == PyObject_DelItem(a, b))
return NULL;
Py_RETURN_NONE;
}
static PyObject *
_operator_eq_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyObject_RichCompare(a, b, Py_EQ);
}
static PyObject *
_operator_ne_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyObject_RichCompare(a, b, Py_NE);
}
static PyObject *
_operator_lt_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyObject_RichCompare(a, b, Py_LT);
}
static PyObject *
_operator_le_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyObject_RichCompare(a, b, Py_LE);
}
static PyObject *
_operator_gt_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyObject_RichCompare(a, b, Py_GT);
}
static PyObject *
_operator_ge_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyObject_RichCompare(a, b, Py_GE);
}
static PyObject *
_operator_pow_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_Power(a, b, Py_None);
}
static PyObject *
_operator_ipow_impl(PyObject *module, PyObject *a, PyObject *b)
{
return PyNumber_InPlacePower(a, b, Py_None);
}
static PyObject *
_operator_index(PyObject *module, PyObject *a)
{
return PyNumber_Index(a);
}
static PyObject *
_operator_is__impl(PyObject *module, PyObject *a, PyObject *b)
{
PyObject *result = Py_Is(a, b) ? Py_True : Py_False;
return Py_NewRef(result);
}
static PyObject *
_operator_is_not_impl(PyObject *module, PyObject *a, PyObject *b)
{
PyObject *result;
result = (a != b) ? Py_True : Py_False;
return Py_NewRef(result);
}
static int
_tscmp(const unsigned char *a, const unsigned char *b,
Py_ssize_t len_a, Py_ssize_t len_b)
{
volatile Py_ssize_t length;
volatile const unsigned char *left;
volatile const unsigned char *right;
Py_ssize_t i;
volatile unsigned char result;
length = len_b;
left = NULL;
right = b;
if (len_a == length) {
left = *((volatile const unsigned char**)&a);
result = 0;
}
if (len_a != length) {
left = b;
result = 1;
}
for (i=0; i < length; i++) {
result |= *left++ ^ *right++;
}
return (result == 0);
}
static Py_ssize_t
_operator_length_hint_impl(PyObject *module, PyObject *obj,
Py_ssize_t default_value)
{
return PyObject_LengthHint(obj, default_value);
}
static PyObject *
_operator__compare_digest_impl(PyObject *module, PyObject *a, PyObject *b)
{
int rc;
if(PyUnicode_Check(a) && PyUnicode_Check(b)) {
if (!PyUnicode_IS_ASCII(a) || !PyUnicode_IS_ASCII(b)) {
PyErr_SetString(PyExc_TypeError,
"comparing strings with non-ASCII characters is "
"not supported");
return NULL;
}
rc = _tscmp(PyUnicode_DATA(a),
PyUnicode_DATA(b),
PyUnicode_GET_LENGTH(a),
PyUnicode_GET_LENGTH(b));
}
else {
Py_buffer view_a;
Py_buffer view_b;
if (PyObject_CheckBuffer(a) == 0 && PyObject_CheckBuffer(b) == 0) {
PyErr_Format(PyExc_TypeError,
"unsupported operand types(s) or combination of types: "
"'%.100s' and '%.100s'",
Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);
return NULL;
}
if (PyObject_GetBuffer(a, &view_a, PyBUF_SIMPLE) == -1) {
return NULL;
}
if (view_a.ndim > 1) {
PyErr_SetString(PyExc_BufferError,
"Buffer must be single dimension");
PyBuffer_Release(&view_a);
return NULL;
}
if (PyObject_GetBuffer(b, &view_b, PyBUF_SIMPLE) == -1) {
PyBuffer_Release(&view_a);
return NULL;
}
if (view_b.ndim > 1) {
PyErr_SetString(PyExc_BufferError,
"Buffer must be single dimension");
PyBuffer_Release(&view_a);
PyBuffer_Release(&view_b);
return NULL;
}
rc = _tscmp((const unsigned char*)view_a.buf,
(const unsigned char*)view_b.buf,
view_a.len,
view_b.len);
PyBuffer_Release(&view_a);
PyBuffer_Release(&view_b);
}
return PyBool_FromLong(rc);
}
PyDoc_STRVAR(_operator_call__doc__,
"call($module, obj, /, *args, **kwargs)\n"
"--\n"
"\n"
"Same as obj(*args, **kwargs).");
#define _OPERATOR_CALL_METHODDEF \
{"call", _PyCFunction_CAST(_operator_call), METH_FASTCALL | METH_KEYWORDS, _operator_call__doc__},
static PyObject *
_operator_call(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
if (!_PyArg_CheckPositional("call", nargs, 1, PY_SSIZE_T_MAX)) {
return NULL;
}
return PyObject_Vectorcall(
args[0],
&args[1], (PyVectorcall_NARGS(nargs) - 1) | PY_VECTORCALL_ARGUMENTS_OFFSET,
kwnames);
}
static struct PyMethodDef operator_methods[] = {
_OPERATOR_TRUTH_METHODDEF
_OPERATOR_CONTAINS_METHODDEF
_OPERATOR_INDEXOF_METHODDEF
_OPERATOR_COUNTOF_METHODDEF
_OPERATOR_IS__METHODDEF
_OPERATOR_IS_NOT_METHODDEF
_OPERATOR_INDEX_METHODDEF
_OPERATOR_ADD_METHODDEF
_OPERATOR_SUB_METHODDEF
_OPERATOR_MUL_METHODDEF
_OPERATOR_MATMUL_METHODDEF
_OPERATOR_FLOORDIV_METHODDEF
_OPERATOR_TRUEDIV_METHODDEF
_OPERATOR_MOD_METHODDEF
_OPERATOR_NEG_METHODDEF
_OPERATOR_POS_METHODDEF
_OPERATOR_ABS_METHODDEF
_OPERATOR_INV_METHODDEF
_OPERATOR_INVERT_METHODDEF
_OPERATOR_LSHIFT_METHODDEF
_OPERATOR_RSHIFT_METHODDEF
_OPERATOR_NOT__METHODDEF
_OPERATOR_AND__METHODDEF
_OPERATOR_XOR_METHODDEF
_OPERATOR_OR__METHODDEF
_OPERATOR_IADD_METHODDEF
_OPERATOR_ISUB_METHODDEF
_OPERATOR_IMUL_METHODDEF
_OPERATOR_IMATMUL_METHODDEF
_OPERATOR_IFLOORDIV_METHODDEF
_OPERATOR_ITRUEDIV_METHODDEF
_OPERATOR_IMOD_METHODDEF
_OPERATOR_ILSHIFT_METHODDEF
_OPERATOR_IRSHIFT_METHODDEF
_OPERATOR_IAND_METHODDEF
_OPERATOR_IXOR_METHODDEF
_OPERATOR_IOR_METHODDEF
_OPERATOR_CONCAT_METHODDEF
_OPERATOR_ICONCAT_METHODDEF
_OPERATOR_GETITEM_METHODDEF
_OPERATOR_SETITEM_METHODDEF
_OPERATOR_DELITEM_METHODDEF
_OPERATOR_POW_METHODDEF
_OPERATOR_IPOW_METHODDEF
_OPERATOR_EQ_METHODDEF
_OPERATOR_NE_METHODDEF
_OPERATOR_LT_METHODDEF
_OPERATOR_LE_METHODDEF
_OPERATOR_GT_METHODDEF
_OPERATOR_GE_METHODDEF
_OPERATOR__COMPARE_DIGEST_METHODDEF
_OPERATOR_LENGTH_HINT_METHODDEF
_OPERATOR_CALL_METHODDEF
{NULL, NULL}
};
typedef struct {
PyObject_HEAD
Py_ssize_t nitems;
PyObject *item;
Py_ssize_t index;
vectorcallfunc vectorcall;
} itemgetterobject;
static PyObject *
itemgetter_vectorcall(PyObject *, PyObject *const *, size_t, PyObject *);
static PyObject *
itemgetter_call_impl(itemgetterobject *, PyObject *);
static PyObject *
itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
itemgetterobject *ig;
PyObject *item;
Py_ssize_t nitems;
Py_ssize_t index;
if (!_PyArg_NoKeywords("itemgetter", kwds))
return NULL;
nitems = PyTuple_GET_SIZE(args);
if (nitems <= 1) {
if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &item))
return NULL;
} else {
item = args;
}
_operator_state *state = _PyType_GetModuleState(type);
ig = PyObject_GC_New(itemgetterobject, (PyTypeObject *) state->itemgetter_type);
if (ig == NULL) {
return NULL;
}
ig->item = Py_NewRef(item);
ig->nitems = nitems;
ig->index = -1;
if (PyLong_CheckExact(item)) {
index = PyLong_AsSsize_t(item);
if (index < 0) {
PyErr_Clear();
}
else {
ig->index = index;
}
}
ig->vectorcall = (vectorcallfunc)itemgetter_vectorcall;
PyObject_GC_Track(ig);
return (PyObject *)ig;
}
static int
itemgetter_clear(itemgetterobject *ig)
{
Py_CLEAR(ig->item);
return 0;
}
static void
itemgetter_dealloc(itemgetterobject *ig)
{
PyTypeObject *tp = Py_TYPE(ig);
PyObject_GC_UnTrack(ig);
(void)itemgetter_clear(ig);
tp->tp_free(ig);
Py_DECREF(tp);
}
static int
itemgetter_traverse(itemgetterobject *ig, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(ig));
Py_VISIT(ig->item);
return 0;
}
static PyObject *
itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw)
{
assert(PyTuple_CheckExact(args));
if (!_PyArg_NoKeywords("itemgetter", kw))
return NULL;
if (!_PyArg_CheckPositional("itemgetter", PyTuple_GET_SIZE(args), 1, 1))
return NULL;
return itemgetter_call_impl(ig, PyTuple_GET_ITEM(args, 0));
}
static PyObject *
itemgetter_vectorcall(PyObject *ig, PyObject *const *args,
size_t nargsf, PyObject *kwnames)
{
if (!_PyArg_NoKwnames("itemgetter", kwnames)) {
return NULL;
}
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (!_PyArg_CheckPositional("itemgetter", nargs, 1, 1)) {
return NULL;
}
return itemgetter_call_impl((itemgetterobject *)ig, args[0]);
}
static PyObject *
itemgetter_call_impl(itemgetterobject *ig, PyObject *obj)
{
PyObject *result;
Py_ssize_t i, nitems=ig->nitems;
if (nitems == 1) {
if (ig->index >= 0
&& PyTuple_CheckExact(obj)
&& ig->index < PyTuple_GET_SIZE(obj))
{
result = PyTuple_GET_ITEM(obj, ig->index);
return Py_NewRef(result);
}
return PyObject_GetItem(obj, ig->item);
}
assert(PyTuple_Check(ig->item));
assert(PyTuple_GET_SIZE(ig->item) == nitems);
result = PyTuple_New(nitems);
if (result == NULL)
return NULL;
for (i=0 ; i < nitems ; i++) {
PyObject *item, *val;
item = PyTuple_GET_ITEM(ig->item, i);
val = PyObject_GetItem(obj, item);
if (val == NULL) {
Py_DECREF(result);
return NULL;
}
PyTuple_SET_ITEM(result, i, val);
}
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, PyObject *Py_UNUSED(ignored))
{
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}
};
static PyMemberDef itemgetter_members[] = {
{"__vectorcalloffset__", T_PYSSIZET, offsetof(itemgetterobject, vectorcall), READONLY},
{NULL}
};
PyDoc_STRVAR(itemgetter_doc,
"itemgetter(item, /, *items)\n--\n\n\
Return a callable object that fetches the given item(s) from its operand.\n\
After f = itemgetter(2), the call f(r) returns r[2].\n\
After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])");
static PyType_Slot itemgetter_type_slots[] = {
{Py_tp_doc, (void *)itemgetter_doc},
{Py_tp_dealloc, itemgetter_dealloc},
{Py_tp_call, itemgetter_call},
{Py_tp_traverse, itemgetter_traverse},
{Py_tp_clear, itemgetter_clear},
{Py_tp_methods, itemgetter_methods},
{Py_tp_members, itemgetter_members},
{Py_tp_new, itemgetter_new},
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_repr, itemgetter_repr},
{0, 0}
};
static PyType_Spec itemgetter_type_spec = {
.name = "operator.itemgetter",
.basicsize = sizeof(itemgetterobject),
.itemsize = 0,
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_VECTORCALL),
.slots = itemgetter_type_slots,
};
typedef struct {
PyObject_HEAD
Py_ssize_t nattrs;
PyObject *attr;
vectorcallfunc vectorcall;
} attrgetterobject;
static PyObject *
attrgetter_vectorcall(PyObject *, PyObject *const *, size_t, PyObject *);
static PyObject *
attrgetter_call_impl(attrgetterobject *, PyObject *);
static PyObject *
attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
attrgetterobject *ag;
PyObject *attr;
Py_ssize_t nattrs, idx, char_idx;
if (!_PyArg_NoKeywords("attrgetter", kwds))
return NULL;
nattrs = PyTuple_GET_SIZE(args);
if (nattrs <= 1) {
if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &attr))
return NULL;
}
attr = PyTuple_New(nattrs);
if (attr == NULL)
return NULL;
for (idx = 0; idx < nattrs; ++idx) {
PyObject *item = PyTuple_GET_ITEM(args, idx);
int dot_count;
if (!PyUnicode_Check(item)) {
PyErr_SetString(PyExc_TypeError,
"attribute name must be a string");
Py_DECREF(attr);
return NULL;
}
Py_ssize_t item_len = PyUnicode_GET_LENGTH(item);
int kind = PyUnicode_KIND(item);
const void *data = PyUnicode_DATA(item);
dot_count = 0;
for (char_idx = 0; char_idx < item_len; ++char_idx) {
if (PyUnicode_READ(kind, data, char_idx) == '.')
++dot_count;
}
if (dot_count == 0) {
Py_INCREF(item);
PyUnicode_InternInPlace(&item);
PyTuple_SET_ITEM(attr, idx, item);
} else {
PyObject *attr_chain = PyTuple_New(dot_count + 1);
PyObject *attr_chain_item;
Py_ssize_t unibuff_from = 0;
Py_ssize_t unibuff_till = 0;
Py_ssize_t attr_chain_idx = 0;
if (attr_chain == NULL) {
Py_DECREF(attr);
return NULL;
}
for (; dot_count > 0; --dot_count) {
while (PyUnicode_READ(kind, data, unibuff_till) != '.') {
++unibuff_till;
}
attr_chain_item = PyUnicode_Substring(item,
unibuff_from,
unibuff_till);
if (attr_chain_item == NULL) {
Py_DECREF(attr_chain);
Py_DECREF(attr);
return NULL;
}
PyUnicode_InternInPlace(&attr_chain_item);
PyTuple_SET_ITEM(attr_chain, attr_chain_idx, attr_chain_item);
++attr_chain_idx;
unibuff_till = unibuff_from = unibuff_till + 1;
}
attr_chain_item = PyUnicode_Substring(item,
unibuff_from, item_len);
if (attr_chain_item == NULL) {
Py_DECREF(attr_chain);
Py_DECREF(attr);
return NULL;
}
PyUnicode_InternInPlace(&attr_chain_item);
PyTuple_SET_ITEM(attr_chain, attr_chain_idx, attr_chain_item);
PyTuple_SET_ITEM(attr, idx, attr_chain);
}
}
_operator_state *state = _PyType_GetModuleState(type);
ag = PyObject_GC_New(attrgetterobject, (PyTypeObject *)state->attrgetter_type);
if (ag == NULL) {
Py_DECREF(attr);
return NULL;
}
ag->attr = attr;
ag->nattrs = nattrs;
ag->vectorcall = (vectorcallfunc)attrgetter_vectorcall;
PyObject_GC_Track(ag);
return (PyObject *)ag;
}
static int
attrgetter_clear(attrgetterobject *ag)
{
Py_CLEAR(ag->attr);
return 0;
}
static void
attrgetter_dealloc(attrgetterobject *ag)
{
PyTypeObject *tp = Py_TYPE(ag);
PyObject_GC_UnTrack(ag);
(void)attrgetter_clear(ag);
tp->tp_free(ag);
Py_DECREF(tp);
}
static int
attrgetter_traverse(attrgetterobject *ag, visitproc visit, void *arg)
{
Py_VISIT(ag->attr);
Py_VISIT(Py_TYPE(ag));
return 0;
}
static PyObject *
dotted_getattr(PyObject *obj, PyObject *attr)
{
PyObject *newobj;
if (PyTuple_CheckExact(attr)) {
Py_ssize_t name_idx = 0, name_count;
PyObject *attr_name;
name_count = PyTuple_GET_SIZE(attr);
Py_INCREF(obj);
for (name_idx = 0; name_idx < name_count; ++name_idx) {
attr_name = PyTuple_GET_ITEM(attr, name_idx);
newobj = PyObject_GetAttr(obj, attr_name);
Py_DECREF(obj);
if (newobj == NULL) {
return NULL;
}
obj = newobj;
}
} else {
newobj = PyObject_GetAttr(obj, attr);
if (newobj == NULL)
return NULL;
obj = newobj;
}
return obj;
}
static PyObject *
attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw)
{
if (!_PyArg_NoKeywords("attrgetter", kw))
return NULL;
if (!_PyArg_CheckPositional("attrgetter", PyTuple_GET_SIZE(args), 1, 1))
return NULL;
return attrgetter_call_impl(ag, PyTuple_GET_ITEM(args, 0));
}
static PyObject *
attrgetter_vectorcall(PyObject *ag, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{
if (!_PyArg_NoKwnames("attrgetter", kwnames)) {
return NULL;
}
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (!_PyArg_CheckPositional("attrgetter", nargs, 1, 1)) {
return NULL;
}
return attrgetter_call_impl((attrgetterobject *)ag, args[0]);
}
static PyObject *
attrgetter_call_impl(attrgetterobject *ag, PyObject *obj)
{
PyObject *result;
Py_ssize_t i, nattrs=ag->nattrs;
if (ag->nattrs == 1) {
return dotted_getattr(obj, PyTuple_GET_ITEM(ag->attr, 0));
}
assert(PyTuple_Check(ag->attr));
assert(PyTuple_GET_SIZE(ag->attr) == nattrs);
result = PyTuple_New(nattrs);
if (result == NULL)
return NULL;
for (i=0 ; i < nattrs ; i++) {
PyObject *attr, *val;
attr = PyTuple_GET_ITEM(ag->attr, i);
val = dotted_getattr(obj, attr);
if (val == NULL) {
Py_DECREF(result);
return NULL;
}
PyTuple_SET_ITEM(result, i, val);
}
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 {
return Py_NewRef(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 *Py_UNUSED(ignored))
{
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}
};
static PyMemberDef attrgetter_members[] = {
{"__vectorcalloffset__", T_PYSSIZET, offsetof(attrgetterobject, vectorcall), READONLY},
{NULL}
};
PyDoc_STRVAR(attrgetter_doc,
"attrgetter(attr, /, *attrs)\n--\n\n\
Return a callable object that fetches the given attribute(s) from its operand.\n\
After f = attrgetter('name'), the call f(r) returns r.name.\n\
After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\
After h = attrgetter('name.first', 'name.last'), the call h(r) returns\n\
(r.name.first, r.name.last).");
static PyType_Slot attrgetter_type_slots[] = {
{Py_tp_doc, (void *)attrgetter_doc},
{Py_tp_dealloc, attrgetter_dealloc},
{Py_tp_call, attrgetter_call},
{Py_tp_traverse, attrgetter_traverse},
{Py_tp_clear, attrgetter_clear},
{Py_tp_methods, attrgetter_methods},
{Py_tp_members, attrgetter_members},
{Py_tp_new, attrgetter_new},
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_repr, attrgetter_repr},
{0, 0}
};
static PyType_Spec attrgetter_type_spec = {
.name = "operator.attrgetter",
.basicsize = sizeof(attrgetterobject),
.itemsize = 0,
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_VECTORCALL),
.slots = attrgetter_type_slots,
};
typedef struct {
PyObject_HEAD
PyObject *name;
PyObject *args;
PyObject *kwds;
} methodcallerobject;
static PyObject *
methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
methodcallerobject *mc;
PyObject *name;
if (PyTuple_GET_SIZE(args) < 1) {
PyErr_SetString(PyExc_TypeError, "methodcaller needs at least "
"one argument, the method name");
return NULL;
}
name = PyTuple_GET_ITEM(args, 0);
if (!PyUnicode_Check(name)) {
PyErr_SetString(PyExc_TypeError,
"method name must be a string");
return NULL;
}
_operator_state *state = _PyType_GetModuleState(type);
mc = PyObject_GC_New(methodcallerobject, (PyTypeObject *)state->methodcaller_type);
if (mc == NULL) {
return NULL;
}
name = PyTuple_GET_ITEM(args, 0);
Py_INCREF(name);
PyUnicode_InternInPlace(&name);
mc->name = name;
mc->kwds = Py_XNewRef(kwds);
mc->args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
if (mc->args == NULL) {
Py_DECREF(mc);
return NULL;
}
PyObject_GC_Track(mc);
return (PyObject *)mc;
}
static int
methodcaller_clear(methodcallerobject *mc)
{
Py_CLEAR(mc->name);
Py_CLEAR(mc->args);
Py_CLEAR(mc->kwds);
return 0;
}
static void
methodcaller_dealloc(methodcallerobject *mc)
{
PyTypeObject *tp = Py_TYPE(mc);
PyObject_GC_UnTrack(mc);
(void)methodcaller_clear(mc);
tp->tp_free(mc);
Py_DECREF(tp);
}
static int
methodcaller_traverse(methodcallerobject *mc, visitproc visit, void *arg)
{
Py_VISIT(mc->name);
Py_VISIT(mc->args);
Py_VISIT(mc->kwds);
Py_VISIT(Py_TYPE(mc));
return 0;
}
static PyObject *
methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw)
{
PyObject *method, *obj, *result;
if (!_PyArg_NoKeywords("methodcaller", kw))
return NULL;
if (!_PyArg_CheckPositional("methodcaller", PyTuple_GET_SIZE(args), 1, 1))
return NULL;
obj = PyTuple_GET_ITEM(args, 0);
method = PyObject_GetAttr(obj, mc->name);
if (method == NULL)
return NULL;
result = PyObject_Call(method, mc->args, mc->kwds);
Py_DECREF(method);
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);
}
numkwdargs = mc->kwds != NULL ? PyDict_GET_SIZE(mc->kwds) : 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;
Py_DECREF(onerepr);
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 *Py_UNUSED(ignored))
{
PyObject *newargs;
if (!mc->kwds || PyDict_GET_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;
PyTuple_SET_ITEM(newargs, 0, Py_NewRef(mc->name));
for (i = 0; i < callargcount; ++i) {
PyObject *arg = PyTuple_GET_ITEM(mc->args, i);
PyTuple_SET_ITEM(newargs, i + 1, Py_NewRef(arg));
}
return Py_BuildValue("ON", Py_TYPE(mc), newargs);
}
else {
PyObject *partial;
PyObject *constructor;
PyObject *newargs[2];
partial = _PyImport_GetModuleAttrString("functools", "partial");
if (!partial)
return NULL;
newargs[0] = (PyObject *)Py_TYPE(mc);
newargs[1] = mc->name;
constructor = PyObject_VectorcallDict(partial, newargs, 2, mc->kwds);
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, /, *args, **kwargs)\n--\n\n\
Return a callable object that calls the given method on its operand.\n\
After f = methodcaller('name'), the call f(r) returns r.name().\n\
After g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\
r.name('date', foo=1).");
static PyType_Slot methodcaller_type_slots[] = {
{Py_tp_doc, (void *)methodcaller_doc},
{Py_tp_dealloc, methodcaller_dealloc},
{Py_tp_call, methodcaller_call},
{Py_tp_traverse, methodcaller_traverse},
{Py_tp_clear, methodcaller_clear},
{Py_tp_methods, methodcaller_methods},
{Py_tp_new, methodcaller_new},
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_repr, methodcaller_repr},
{0, 0}
};
static PyType_Spec methodcaller_type_spec = {
.name = "operator.methodcaller",
.basicsize = sizeof(methodcallerobject),
.itemsize = 0,
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = methodcaller_type_slots,
};
static int
operator_exec(PyObject *module)
{
_operator_state *state = get_operator_state(module);
state->attrgetter_type = PyType_FromModuleAndSpec(module, &attrgetter_type_spec, NULL);
if (state->attrgetter_type == NULL) {
return -1;
}
if (PyModule_AddType(module, (PyTypeObject *)state->attrgetter_type) < 0) {
return -1;
}
state->itemgetter_type = PyType_FromModuleAndSpec(module, &itemgetter_type_spec, NULL);
if (state->itemgetter_type == NULL) {
return -1;
}
if (PyModule_AddType(module, (PyTypeObject *)state->itemgetter_type) < 0) {
return -1;
}
state->methodcaller_type = PyType_FromModuleAndSpec(module, &methodcaller_type_spec, NULL);
if (state->methodcaller_type == NULL) {
return -1;
}
if (PyModule_AddType(module, (PyTypeObject *)state->methodcaller_type) < 0) {
return -1;
}
return 0;
}
static struct PyModuleDef_Slot operator_slots[] = {
{Py_mod_exec, operator_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL}
};
static int
operator_traverse(PyObject *module, visitproc visit, void *arg)
{
_operator_state *state = get_operator_state(module);
Py_VISIT(state->attrgetter_type);
Py_VISIT(state->itemgetter_type);
Py_VISIT(state->methodcaller_type);
return 0;
}
static int
operator_clear(PyObject *module)
{
_operator_state *state = get_operator_state(module);
Py_CLEAR(state->attrgetter_type);
Py_CLEAR(state->itemgetter_type);
Py_CLEAR(state->methodcaller_type);
return 0;
}
static void
operator_free(void *module)
{
operator_clear((PyObject *)module);
}
static struct PyModuleDef operatormodule = {
PyModuleDef_HEAD_INIT,
.m_name = "_operator",
.m_doc = operator_doc,
.m_size = sizeof(_operator_state),
.m_methods = operator_methods,
.m_slots = operator_slots,
.m_traverse = operator_traverse,
.m_clear = operator_clear,
.m_free = operator_free,
};
PyMODINIT_FUNC
PyInit__operator(void)
{
return PyModuleDef_Init(&operatormodule);
}