+++ /dev/null
-\r
-#include "Python.h"\r
-#include "structmember.h"\r
-\r
-/* _functools module written and maintained\r
- by Hye-Shik Chang <perky@FreeBSD.org>\r
- with adaptations by Raymond Hettinger <python@rcn.com>\r
- Copyright (c) 2004, 2005, 2006 Python Software Foundation.\r
- All rights reserved.\r
-*/\r
-\r
-/* reduce() *************************************************************/\r
-\r
-static PyObject *\r
-functools_reduce(PyObject *self, PyObject *args)\r
-{\r
- PyObject *seq, *func, *result = NULL, *it;\r
-\r
- if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))\r
- return NULL;\r
- if (result != NULL)\r
- Py_INCREF(result);\r
-\r
- it = PyObject_GetIter(seq);\r
- if (it == NULL) {\r
- PyErr_SetString(PyExc_TypeError,\r
- "reduce() arg 2 must support iteration");\r
- Py_XDECREF(result);\r
- return NULL;\r
- }\r
-\r
- if ((args = PyTuple_New(2)) == NULL)\r
- goto Fail;\r
-\r
- for (;;) {\r
- PyObject *op2;\r
-\r
- if (args->ob_refcnt > 1) {\r
- Py_DECREF(args);\r
- if ((args = PyTuple_New(2)) == NULL)\r
- goto Fail;\r
- }\r
-\r
- op2 = PyIter_Next(it);\r
- if (op2 == NULL) {\r
- if (PyErr_Occurred())\r
- goto Fail;\r
- break;\r
- }\r
-\r
- if (result == NULL)\r
- result = op2;\r
- else {\r
- PyTuple_SetItem(args, 0, result);\r
- PyTuple_SetItem(args, 1, op2);\r
- if ((result = PyEval_CallObject(func, args)) == NULL)\r
- goto Fail;\r
- }\r
- }\r
-\r
- Py_DECREF(args);\r
-\r
- if (result == NULL)\r
- PyErr_SetString(PyExc_TypeError,\r
- "reduce() of empty sequence with no initial value");\r
-\r
- Py_DECREF(it);\r
- return result;\r
-\r
-Fail:\r
- Py_XDECREF(args);\r
- Py_XDECREF(result);\r
- Py_DECREF(it);\r
- return NULL;\r
-}\r
-\r
-PyDoc_STRVAR(reduce_doc,\r
-"reduce(function, sequence[, initial]) -> value\n\\r
-\n\\r
-Apply a function of two arguments cumulatively to the items of a sequence,\n\\r
-from left to right, so as to reduce the sequence to a single value.\n\\r
-For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\\r
-((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\\r
-of the sequence in the calculation, and serves as a default when the\n\\r
-sequence is empty.");\r
-\r
-\r
-\r
-\r
-/* partial object **********************************************************/\r
-\r
-typedef struct {\r
- PyObject_HEAD\r
- PyObject *fn;\r
- PyObject *args;\r
- PyObject *kw;\r
- PyObject *dict;\r
- PyObject *weakreflist; /* List of weak references */\r
-} partialobject;\r
-\r
-static PyTypeObject partial_type;\r
-\r
-static PyObject *\r
-partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)\r
-{\r
- PyObject *func;\r
- partialobject *pto;\r
-\r
- if (PyTuple_GET_SIZE(args) < 1) {\r
- PyErr_SetString(PyExc_TypeError,\r
- "type 'partial' takes at least one argument");\r
- return NULL;\r
- }\r
-\r
- func = PyTuple_GET_ITEM(args, 0);\r
- if (!PyCallable_Check(func)) {\r
- PyErr_SetString(PyExc_TypeError,\r
- "the first argument must be callable");\r
- return NULL;\r
- }\r
-\r
- /* create partialobject structure */\r
- pto = (partialobject *)type->tp_alloc(type, 0);\r
- if (pto == NULL)\r
- return NULL;\r
-\r
- pto->fn = func;\r
- Py_INCREF(func);\r
- pto->args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);\r
- if (pto->args == NULL) {\r
- pto->kw = NULL;\r
- Py_DECREF(pto);\r
- return NULL;\r
- }\r
- pto->kw = (kw != NULL) ? PyDict_Copy(kw) : PyDict_New();\r
- if (pto->kw == NULL) {\r
- Py_DECREF(pto);\r
- return NULL;\r
- }\r
-\r
-\r
- pto->weakreflist = NULL;\r
- pto->dict = NULL;\r
-\r
- return (PyObject *)pto;\r
-}\r
-\r
-static void\r
-partial_dealloc(partialobject *pto)\r
-{\r
- PyObject_GC_UnTrack(pto);\r
- if (pto->weakreflist != NULL)\r
- PyObject_ClearWeakRefs((PyObject *) pto);\r
- Py_XDECREF(pto->fn);\r
- Py_XDECREF(pto->args);\r
- Py_XDECREF(pto->kw);\r
- Py_XDECREF(pto->dict);\r
- Py_TYPE(pto)->tp_free(pto);\r
-}\r
-\r
-static PyObject *\r
-partial_call(partialobject *pto, PyObject *args, PyObject *kw)\r
-{\r
- PyObject *ret;\r
- PyObject *argappl = NULL, *kwappl = NULL;\r
-\r
- assert (PyCallable_Check(pto->fn));\r
- assert (PyTuple_Check(pto->args));\r
- assert (pto->kw == Py_None || PyDict_Check(pto->kw));\r
-\r
- if (PyTuple_GET_SIZE(pto->args) == 0) {\r
- argappl = args;\r
- Py_INCREF(args);\r
- } else if (PyTuple_GET_SIZE(args) == 0) {\r
- argappl = pto->args;\r
- Py_INCREF(pto->args);\r
- } else {\r
- argappl = PySequence_Concat(pto->args, args);\r
- if (argappl == NULL)\r
- return NULL;\r
- }\r
-\r
- if (pto->kw == Py_None) {\r
- kwappl = kw;\r
- Py_XINCREF(kw);\r
- } else {\r
- kwappl = PyDict_Copy(pto->kw);\r
- if (kwappl == NULL) {\r
- Py_DECREF(argappl);\r
- return NULL;\r
- }\r
- if (kw != NULL) {\r
- if (PyDict_Merge(kwappl, kw, 1) != 0) {\r
- Py_DECREF(argappl);\r
- Py_DECREF(kwappl);\r
- return NULL;\r
- }\r
- }\r
- }\r
-\r
- ret = PyObject_Call(pto->fn, argappl, kwappl);\r
- Py_DECREF(argappl);\r
- Py_XDECREF(kwappl);\r
- return ret;\r
-}\r
-\r
-static int\r
-partial_traverse(partialobject *pto, visitproc visit, void *arg)\r
-{\r
- Py_VISIT(pto->fn);\r
- Py_VISIT(pto->args);\r
- Py_VISIT(pto->kw);\r
- Py_VISIT(pto->dict);\r
- return 0;\r
-}\r
-\r
-PyDoc_STRVAR(partial_doc,\r
-"partial(func, *args, **keywords) - new function with partial application\n\\r
- of the given arguments and keywords.\n");\r
-\r
-#define OFF(x) offsetof(partialobject, x)\r
-static PyMemberDef partial_memberlist[] = {\r
- {"func", T_OBJECT, OFF(fn), READONLY,\r
- "function object to use in future partial calls"},\r
- {"args", T_OBJECT, OFF(args), READONLY,\r
- "tuple of arguments to future partial calls"},\r
- {"keywords", T_OBJECT, OFF(kw), READONLY,\r
- "dictionary of keyword arguments to future partial calls"},\r
- {NULL} /* Sentinel */\r
-};\r
-\r
-static PyObject *\r
-partial_get_dict(partialobject *pto)\r
-{\r
- if (pto->dict == NULL) {\r
- pto->dict = PyDict_New();\r
- if (pto->dict == NULL)\r
- return NULL;\r
- }\r
- Py_INCREF(pto->dict);\r
- return pto->dict;\r
-}\r
-\r
-static int\r
-partial_set_dict(partialobject *pto, PyObject *value)\r
-{\r
- PyObject *tmp;\r
-\r
- /* It is illegal to del p.__dict__ */\r
- if (value == NULL) {\r
- PyErr_SetString(PyExc_TypeError,\r
- "a partial object's dictionary may not be deleted");\r
- return -1;\r
- }\r
- /* Can only set __dict__ to a dictionary */\r
- if (!PyDict_Check(value)) {\r
- PyErr_SetString(PyExc_TypeError,\r
- "setting partial object's dictionary to a non-dict");\r
- return -1;\r
- }\r
- tmp = pto->dict;\r
- Py_INCREF(value);\r
- pto->dict = value;\r
- Py_XDECREF(tmp);\r
- return 0;\r
-}\r
-\r
-static PyGetSetDef partial_getsetlist[] = {\r
- {"__dict__", (getter)partial_get_dict, (setter)partial_set_dict},\r
- {NULL} /* Sentinel */\r
-};\r
-\r
-/* Pickle strategy:\r
- __reduce__ by itself doesn't support getting kwargs in the unpickle\r
- operation so we define a __setstate__ that replaces all the information\r
- about the partial. If we only replaced part of it someone would use\r
- it as a hook to do strange things.\r
- */\r
-\r
-PyObject *\r
-partial_reduce(partialobject *pto, PyObject *unused)\r
-{\r
- return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,\r
- pto->args, pto->kw,\r
- pto->dict ? pto->dict : Py_None);\r
-}\r
-\r
-PyObject *\r
-partial_setstate(partialobject *pto, PyObject *state)\r
-{\r
- PyObject *fn, *fnargs, *kw, *dict;\r
- if (!PyArg_ParseTuple(state, "OOOO",\r
- &fn, &fnargs, &kw, &dict))\r
- return NULL;\r
- Py_XDECREF(pto->fn);\r
- Py_XDECREF(pto->args);\r
- Py_XDECREF(pto->kw);\r
- Py_XDECREF(pto->dict);\r
- pto->fn = fn;\r
- pto->args = fnargs;\r
- pto->kw = kw;\r
- if (dict != Py_None) {\r
- pto->dict = dict;\r
- Py_INCREF(dict);\r
- } else {\r
- pto->dict = NULL;\r
- }\r
- Py_INCREF(fn);\r
- Py_INCREF(fnargs);\r
- Py_INCREF(kw);\r
- Py_RETURN_NONE;\r
-}\r
-\r
-static PyMethodDef partial_methods[] = {\r
- {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},\r
- {"__setstate__", (PyCFunction)partial_setstate, METH_O},\r
- {NULL, NULL} /* sentinel */\r
-};\r
-\r
-static PyTypeObject partial_type = {\r
- PyVarObject_HEAD_INIT(NULL, 0)\r
- "functools.partial", /* tp_name */\r
- sizeof(partialobject), /* tp_basicsize */\r
- 0, /* tp_itemsize */\r
- /* methods */\r
- (destructor)partial_dealloc, /* tp_dealloc */\r
- 0, /* tp_print */\r
- 0, /* tp_getattr */\r
- 0, /* tp_setattr */\r
- 0, /* tp_compare */\r
- 0, /* tp_repr */\r
- 0, /* tp_as_number */\r
- 0, /* tp_as_sequence */\r
- 0, /* tp_as_mapping */\r
- 0, /* tp_hash */\r
- (ternaryfunc)partial_call, /* tp_call */\r
- 0, /* tp_str */\r
- PyObject_GenericGetAttr, /* tp_getattro */\r
- PyObject_GenericSetAttr, /* tp_setattro */\r
- 0, /* tp_as_buffer */\r
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |\r
- Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */\r
- partial_doc, /* tp_doc */\r
- (traverseproc)partial_traverse, /* tp_traverse */\r
- 0, /* tp_clear */\r
- 0, /* tp_richcompare */\r
- offsetof(partialobject, weakreflist), /* tp_weaklistoffset */\r
- 0, /* tp_iter */\r
- 0, /* tp_iternext */\r
- partial_methods, /* tp_methods */\r
- partial_memberlist, /* tp_members */\r
- partial_getsetlist, /* tp_getset */\r
- 0, /* tp_base */\r
- 0, /* tp_dict */\r
- 0, /* tp_descr_get */\r
- 0, /* tp_descr_set */\r
- offsetof(partialobject, dict), /* tp_dictoffset */\r
- 0, /* tp_init */\r
- 0, /* tp_alloc */\r
- partial_new, /* tp_new */\r
- PyObject_GC_Del, /* tp_free */\r
-};\r
-\r
-\r
-/* module level code ********************************************************/\r
-\r
-PyDoc_STRVAR(module_doc,\r
-"Tools that operate on functions.");\r
-\r
-static PyMethodDef module_methods[] = {\r
- {"reduce", functools_reduce, METH_VARARGS, reduce_doc},\r
- {NULL, NULL} /* sentinel */\r
-};\r
-\r
-PyMODINIT_FUNC\r
-init_functools(void)\r
-{\r
- int i;\r
- PyObject *m;\r
- char *name;\r
- PyTypeObject *typelist[] = {\r
- &partial_type,\r
- NULL\r
- };\r
-\r
- m = Py_InitModule3("_functools", module_methods, module_doc);\r
- if (m == NULL)\r
- return;\r
-\r
- for (i=0 ; typelist[i] != NULL ; i++) {\r
- if (PyType_Ready(typelist[i]) < 0)\r
- return;\r
- name = strchr(typelist[i]->tp_name, '.');\r
- assert (name != NULL);\r
- Py_INCREF(typelist[i]);\r
- PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);\r
- }\r
-}\r