| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 1 |  | 
 | 2 | #include "Python.h" | 
 | 3 | #include "structmember.h" | 
 | 4 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 5 | /* _functools module written and maintained | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 6 |    by Hye-Shik Chang <perky@FreeBSD.org> | 
 | 7 |    with adaptations by Raymond Hettinger <python@rcn.com> | 
| Thomas Wouters | 4d70c3d | 2006-06-08 14:42:34 +0000 | [diff] [blame] | 8 |    Copyright (c) 2004, 2005, 2006 Python Software Foundation. | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 9 |    All rights reserved. | 
 | 10 | */ | 
 | 11 |  | 
 | 12 | /* partial object **********************************************************/ | 
 | 13 |  | 
 | 14 | typedef struct { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 15 |     PyObject_HEAD | 
 | 16 |     PyObject *fn; | 
 | 17 |     PyObject *args; | 
 | 18 |     PyObject *kw; | 
 | 19 |     PyObject *dict; | 
 | 20 |     PyObject *weakreflist; /* List of weak references */ | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 21 | } partialobject; | 
 | 22 |  | 
 | 23 | static PyTypeObject partial_type; | 
 | 24 |  | 
 | 25 | static PyObject * | 
 | 26 | partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) | 
 | 27 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 28 |     PyObject *func; | 
 | 29 |     partialobject *pto; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 30 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 31 |     if (PyTuple_GET_SIZE(args) < 1) { | 
 | 32 |         PyErr_SetString(PyExc_TypeError, | 
 | 33 |                         "type 'partial' takes at least one argument"); | 
 | 34 |         return NULL; | 
 | 35 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 36 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 37 |     func = PyTuple_GET_ITEM(args, 0); | 
 | 38 |     if (!PyCallable_Check(func)) { | 
 | 39 |         PyErr_SetString(PyExc_TypeError, | 
 | 40 |                         "the first argument must be callable"); | 
 | 41 |         return NULL; | 
 | 42 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 43 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 44 |     /* create partialobject structure */ | 
 | 45 |     pto = (partialobject *)type->tp_alloc(type, 0); | 
 | 46 |     if (pto == NULL) | 
 | 47 |         return NULL; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 48 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 49 |     pto->fn = func; | 
 | 50 |     Py_INCREF(func); | 
 | 51 |     pto->args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX); | 
 | 52 |     if (pto->args == NULL) { | 
 | 53 |         pto->kw = NULL; | 
 | 54 |         Py_DECREF(pto); | 
 | 55 |         return NULL; | 
 | 56 |     } | 
 | 57 |     if (kw != NULL) { | 
 | 58 |         pto->kw = PyDict_Copy(kw); | 
 | 59 |         if (pto->kw == NULL) { | 
 | 60 |             Py_DECREF(pto); | 
 | 61 |             return NULL; | 
 | 62 |         } | 
 | 63 |     } else { | 
 | 64 |         pto->kw = Py_None; | 
 | 65 |         Py_INCREF(Py_None); | 
 | 66 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 67 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 68 |     pto->weakreflist = NULL; | 
 | 69 |     pto->dict = NULL; | 
| Raymond Hettinger | c8b6d1b | 2005-03-08 06:14:50 +0000 | [diff] [blame] | 70 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 71 |     return (PyObject *)pto; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 72 | } | 
 | 73 |  | 
 | 74 | static void | 
 | 75 | partial_dealloc(partialobject *pto) | 
 | 76 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 77 |     PyObject_GC_UnTrack(pto); | 
 | 78 |     if (pto->weakreflist != NULL) | 
 | 79 |         PyObject_ClearWeakRefs((PyObject *) pto); | 
 | 80 |     Py_XDECREF(pto->fn); | 
 | 81 |     Py_XDECREF(pto->args); | 
 | 82 |     Py_XDECREF(pto->kw); | 
 | 83 |     Py_XDECREF(pto->dict); | 
 | 84 |     Py_TYPE(pto)->tp_free(pto); | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 85 | } | 
 | 86 |  | 
 | 87 | static PyObject * | 
 | 88 | partial_call(partialobject *pto, PyObject *args, PyObject *kw) | 
 | 89 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 90 |     PyObject *ret; | 
 | 91 |     PyObject *argappl = NULL, *kwappl = NULL; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 92 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 93 |     assert (PyCallable_Check(pto->fn)); | 
 | 94 |     assert (PyTuple_Check(pto->args)); | 
 | 95 |     assert (pto->kw == Py_None  ||  PyDict_Check(pto->kw)); | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 96 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 97 |     if (PyTuple_GET_SIZE(pto->args) == 0) { | 
 | 98 |         argappl = args; | 
 | 99 |         Py_INCREF(args); | 
 | 100 |     } else if (PyTuple_GET_SIZE(args) == 0) { | 
 | 101 |         argappl = pto->args; | 
 | 102 |         Py_INCREF(pto->args); | 
 | 103 |     } else { | 
 | 104 |         argappl = PySequence_Concat(pto->args, args); | 
 | 105 |         if (argappl == NULL) | 
 | 106 |             return NULL; | 
 | 107 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 108 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 109 |     if (pto->kw == Py_None) { | 
 | 110 |         kwappl = kw; | 
 | 111 |         Py_XINCREF(kw); | 
 | 112 |     } else { | 
 | 113 |         kwappl = PyDict_Copy(pto->kw); | 
 | 114 |         if (kwappl == NULL) { | 
 | 115 |             Py_DECREF(argappl); | 
 | 116 |             return NULL; | 
 | 117 |         } | 
 | 118 |         if (kw != NULL) { | 
 | 119 |             if (PyDict_Merge(kwappl, kw, 1) != 0) { | 
 | 120 |                 Py_DECREF(argappl); | 
 | 121 |                 Py_DECREF(kwappl); | 
 | 122 |                 return NULL; | 
 | 123 |             } | 
 | 124 |         } | 
 | 125 |     } | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 126 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 127 |     ret = PyObject_Call(pto->fn, argappl, kwappl); | 
 | 128 |     Py_DECREF(argappl); | 
 | 129 |     Py_XDECREF(kwappl); | 
 | 130 |     return ret; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 131 | } | 
 | 132 |  | 
 | 133 | static int | 
 | 134 | partial_traverse(partialobject *pto, visitproc visit, void *arg) | 
 | 135 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 136 |     Py_VISIT(pto->fn); | 
 | 137 |     Py_VISIT(pto->args); | 
 | 138 |     Py_VISIT(pto->kw); | 
 | 139 |     Py_VISIT(pto->dict); | 
 | 140 |     return 0; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 141 | } | 
 | 142 |  | 
 | 143 | PyDoc_STRVAR(partial_doc, | 
 | 144 | "partial(func, *args, **keywords) - new function with partial application\n\ | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 145 |     of the given arguments and keywords.\n"); | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 146 |  | 
 | 147 | #define OFF(x) offsetof(partialobject, x) | 
 | 148 | static PyMemberDef partial_memberlist[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 149 |     {"func",            T_OBJECT,       OFF(fn),        READONLY, | 
 | 150 |      "function object to use in future partial calls"}, | 
 | 151 |     {"args",            T_OBJECT,       OFF(args),      READONLY, | 
 | 152 |      "tuple of arguments to future partial calls"}, | 
 | 153 |     {"keywords",        T_OBJECT,       OFF(kw),        READONLY, | 
 | 154 |      "dictionary of keyword arguments to future partial calls"}, | 
 | 155 |     {NULL}  /* Sentinel */ | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 156 | }; | 
 | 157 |  | 
| Raymond Hettinger | c8b6d1b | 2005-03-08 06:14:50 +0000 | [diff] [blame] | 158 | static PyObject * | 
 | 159 | partial_get_dict(partialobject *pto) | 
 | 160 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 161 |     if (pto->dict == NULL) { | 
 | 162 |         pto->dict = PyDict_New(); | 
 | 163 |         if (pto->dict == NULL) | 
 | 164 |             return NULL; | 
 | 165 |     } | 
 | 166 |     Py_INCREF(pto->dict); | 
 | 167 |     return pto->dict; | 
| Raymond Hettinger | c8b6d1b | 2005-03-08 06:14:50 +0000 | [diff] [blame] | 168 | } | 
 | 169 |  | 
 | 170 | static int | 
 | 171 | partial_set_dict(partialobject *pto, PyObject *value) | 
 | 172 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 173 |     PyObject *tmp; | 
| Raymond Hettinger | c8b6d1b | 2005-03-08 06:14:50 +0000 | [diff] [blame] | 174 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 175 |     /* It is illegal to del p.__dict__ */ | 
 | 176 |     if (value == NULL) { | 
 | 177 |         PyErr_SetString(PyExc_TypeError, | 
 | 178 |                         "a partial object's dictionary may not be deleted"); | 
 | 179 |         return -1; | 
 | 180 |     } | 
 | 181 |     /* Can only set __dict__ to a dictionary */ | 
 | 182 |     if (!PyDict_Check(value)) { | 
 | 183 |         PyErr_SetString(PyExc_TypeError, | 
 | 184 |                         "setting partial object's dictionary to a non-dict"); | 
 | 185 |         return -1; | 
 | 186 |     } | 
 | 187 |     tmp = pto->dict; | 
 | 188 |     Py_INCREF(value); | 
 | 189 |     pto->dict = value; | 
 | 190 |     Py_XDECREF(tmp); | 
 | 191 |     return 0; | 
| Raymond Hettinger | c8b6d1b | 2005-03-08 06:14:50 +0000 | [diff] [blame] | 192 | } | 
 | 193 |  | 
| Georg Brandl | c2fb6c7 | 2006-02-21 17:49:57 +0000 | [diff] [blame] | 194 | static PyGetSetDef partial_getsetlist[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 195 |     {"__dict__", (getter)partial_get_dict, (setter)partial_set_dict}, | 
 | 196 |     {NULL} /* Sentinel */ | 
| Raymond Hettinger | c8b6d1b | 2005-03-08 06:14:50 +0000 | [diff] [blame] | 197 | }; | 
 | 198 |  | 
| Alexander Belopolsky | 41e422a | 2010-12-01 20:05:49 +0000 | [diff] [blame] | 199 | static PyObject * | 
 | 200 | partial_repr(partialobject *pto) | 
 | 201 | { | 
 | 202 |     PyObject *result; | 
 | 203 |     PyObject *arglist; | 
 | 204 |     PyObject *tmp; | 
 | 205 |     Py_ssize_t i, n; | 
 | 206 |  | 
 | 207 |     arglist = PyUnicode_FromString(""); | 
 | 208 |     if (arglist == NULL) { | 
 | 209 |         return NULL; | 
 | 210 |     } | 
 | 211 |     /* Pack positional arguments */ | 
 | 212 |     assert (PyTuple_Check(pto->args)); | 
 | 213 |     n = PyTuple_GET_SIZE(pto->args); | 
 | 214 |     for (i = 0; i < n; i++) { | 
 | 215 |         tmp = PyUnicode_FromFormat("%U, %R", arglist, | 
 | 216 |                                    PyTuple_GET_ITEM(pto->args, i)); | 
 | 217 |         Py_DECREF(arglist); | 
 | 218 |         if (tmp == NULL) | 
 | 219 |             return NULL; | 
 | 220 |         arglist = tmp; | 
 | 221 |     } | 
 | 222 |     /* Pack keyword arguments */ | 
 | 223 |     assert (pto->kw == Py_None  ||  PyDict_Check(pto->kw)); | 
 | 224 |     if (pto->kw != Py_None) { | 
 | 225 |         PyObject *key, *value; | 
 | 226 |         for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) { | 
 | 227 |             tmp = PyUnicode_FromFormat("%U, %U=%R", arglist, | 
 | 228 |                                        key, value); | 
 | 229 |             Py_DECREF(arglist); | 
 | 230 |             if (tmp == NULL) | 
 | 231 |                 return NULL; | 
 | 232 |             arglist = tmp; | 
 | 233 |         } | 
 | 234 |     } | 
 | 235 |     result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name, | 
 | 236 |                                   pto->fn, arglist); | 
 | 237 |     Py_DECREF(arglist); | 
 | 238 |     return result; | 
 | 239 | } | 
 | 240 |  | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 241 | /* Pickle strategy: | 
 | 242 |    __reduce__ by itself doesn't support getting kwargs in the unpickle | 
 | 243 |    operation so we define a __setstate__ that replaces all the information | 
 | 244 |    about the partial.  If we only replaced part of it someone would use | 
| Ezio Melotti | 1392500 | 2011-03-16 11:05:33 +0200 | [diff] [blame] | 245 |    it as a hook to do strange things. | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 246 |  */ | 
 | 247 |  | 
| Antoine Pitrou | 69f7114 | 2009-05-24 21:25:49 +0000 | [diff] [blame] | 248 | static PyObject * | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 249 | partial_reduce(partialobject *pto, PyObject *unused) | 
 | 250 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 251 |     return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn, | 
 | 252 |                          pto->args, pto->kw, | 
 | 253 |                          pto->dict ? pto->dict : Py_None); | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 254 | } | 
 | 255 |  | 
| Antoine Pitrou | 69f7114 | 2009-05-24 21:25:49 +0000 | [diff] [blame] | 256 | static PyObject * | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 257 | partial_setstate(partialobject *pto, PyObject *args) | 
 | 258 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 259 |     PyObject *fn, *fnargs, *kw, *dict; | 
 | 260 |     if (!PyArg_ParseTuple(args, "(OOOO):__setstate__", | 
 | 261 |                           &fn, &fnargs, &kw, &dict)) | 
 | 262 |         return NULL; | 
 | 263 |     Py_XDECREF(pto->fn); | 
 | 264 |     Py_XDECREF(pto->args); | 
 | 265 |     Py_XDECREF(pto->kw); | 
 | 266 |     Py_XDECREF(pto->dict); | 
 | 267 |     pto->fn = fn; | 
 | 268 |     pto->args = fnargs; | 
 | 269 |     pto->kw = kw; | 
 | 270 |     if (dict != Py_None) { | 
 | 271 |       pto->dict = dict; | 
 | 272 |       Py_INCREF(dict); | 
 | 273 |     } else { | 
 | 274 |       pto->dict = NULL; | 
 | 275 |     } | 
 | 276 |     Py_INCREF(fn); | 
 | 277 |     Py_INCREF(fnargs); | 
 | 278 |     Py_INCREF(kw); | 
 | 279 |     Py_RETURN_NONE; | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 280 | } | 
 | 281 |  | 
 | 282 | static PyMethodDef partial_methods[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 283 |     {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS}, | 
 | 284 |     {"__setstate__", (PyCFunction)partial_setstate, METH_VARARGS}, | 
 | 285 |     {NULL,              NULL}           /* sentinel */ | 
| Jack Diederich | e0cbd69 | 2009-04-01 04:27:09 +0000 | [diff] [blame] | 286 | }; | 
 | 287 |  | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 288 | static PyTypeObject partial_type = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 289 |     PyVarObject_HEAD_INIT(NULL, 0) | 
 | 290 |     "functools.partial",                /* tp_name */ | 
 | 291 |     sizeof(partialobject),              /* tp_basicsize */ | 
 | 292 |     0,                                  /* tp_itemsize */ | 
 | 293 |     /* methods */ | 
 | 294 |     (destructor)partial_dealloc,        /* tp_dealloc */ | 
 | 295 |     0,                                  /* tp_print */ | 
 | 296 |     0,                                  /* tp_getattr */ | 
 | 297 |     0,                                  /* tp_setattr */ | 
 | 298 |     0,                                  /* tp_reserved */ | 
| Alexander Belopolsky | 41e422a | 2010-12-01 20:05:49 +0000 | [diff] [blame] | 299 |     (reprfunc)partial_repr,             /* tp_repr */ | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 300 |     0,                                  /* tp_as_number */ | 
 | 301 |     0,                                  /* tp_as_sequence */ | 
 | 302 |     0,                                  /* tp_as_mapping */ | 
 | 303 |     0,                                  /* tp_hash */ | 
 | 304 |     (ternaryfunc)partial_call,          /* tp_call */ | 
 | 305 |     0,                                  /* tp_str */ | 
 | 306 |     PyObject_GenericGetAttr,            /* tp_getattro */ | 
 | 307 |     PyObject_GenericSetAttr,            /* tp_setattro */ | 
 | 308 |     0,                                  /* tp_as_buffer */ | 
 | 309 |     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | | 
 | 310 |         Py_TPFLAGS_BASETYPE,            /* tp_flags */ | 
 | 311 |     partial_doc,                        /* tp_doc */ | 
 | 312 |     (traverseproc)partial_traverse,     /* tp_traverse */ | 
 | 313 |     0,                                  /* tp_clear */ | 
 | 314 |     0,                                  /* tp_richcompare */ | 
 | 315 |     offsetof(partialobject, weakreflist),       /* tp_weaklistoffset */ | 
 | 316 |     0,                                  /* tp_iter */ | 
 | 317 |     0,                                  /* tp_iternext */ | 
 | 318 |     partial_methods,                    /* tp_methods */ | 
 | 319 |     partial_memberlist,                 /* tp_members */ | 
 | 320 |     partial_getsetlist,                 /* tp_getset */ | 
 | 321 |     0,                                  /* tp_base */ | 
 | 322 |     0,                                  /* tp_dict */ | 
 | 323 |     0,                                  /* tp_descr_get */ | 
 | 324 |     0,                                  /* tp_descr_set */ | 
 | 325 |     offsetof(partialobject, dict),      /* tp_dictoffset */ | 
 | 326 |     0,                                  /* tp_init */ | 
 | 327 |     0,                                  /* tp_alloc */ | 
 | 328 |     partial_new,                        /* tp_new */ | 
 | 329 |     PyObject_GC_Del,                    /* tp_free */ | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 330 | }; | 
 | 331 |  | 
 | 332 |  | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 333 | /* cmp_to_key ***************************************************************/ | 
 | 334 |  | 
 | 335 | typedef struct { | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 336 |     PyObject_HEAD | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 337 |     PyObject *cmp; | 
 | 338 |     PyObject *object; | 
 | 339 | } keyobject; | 
 | 340 |  | 
 | 341 | static void | 
 | 342 | keyobject_dealloc(keyobject *ko) | 
 | 343 | { | 
 | 344 |     Py_DECREF(ko->cmp); | 
 | 345 |     Py_XDECREF(ko->object); | 
 | 346 |     PyObject_FREE(ko); | 
 | 347 | } | 
 | 348 |  | 
 | 349 | static int | 
 | 350 | keyobject_traverse(keyobject *ko, visitproc visit, void *arg) | 
 | 351 | { | 
 | 352 |     Py_VISIT(ko->cmp); | 
 | 353 |     if (ko->object) | 
 | 354 |         Py_VISIT(ko->object); | 
 | 355 |     return 0; | 
 | 356 | } | 
 | 357 |  | 
| Benjamin Peterson | 3bd9729 | 2011-04-05 17:25:14 -0500 | [diff] [blame] | 358 | static int | 
 | 359 | keyobject_clear(keyobject *ko) | 
 | 360 | { | 
 | 361 |     Py_CLEAR(ko->cmp); | 
 | 362 |     if (ko->object) | 
 | 363 |         Py_CLEAR(ko->object); | 
 | 364 |     return 0; | 
 | 365 | } | 
 | 366 |  | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 367 | static PyMemberDef keyobject_members[] = { | 
 | 368 |     {"obj", T_OBJECT, | 
 | 369 |      offsetof(keyobject, object), 0, | 
 | 370 |      PyDoc_STR("Value wrapped by a key function.")}, | 
 | 371 |     {NULL} | 
 | 372 | }; | 
 | 373 |  | 
 | 374 | static PyObject * | 
| Raymond Hettinger | a563286 | 2011-04-09 12:57:00 -0700 | [diff] [blame] | 375 | keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds); | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 376 |  | 
 | 377 | static PyObject * | 
 | 378 | keyobject_richcompare(PyObject *ko, PyObject *other, int op); | 
 | 379 |  | 
 | 380 | static PyTypeObject keyobject_type = { | 
 | 381 |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | 
 | 382 |     "functools.KeyWrapper",             /* tp_name */ | 
 | 383 |     sizeof(keyobject),                  /* tp_basicsize */ | 
 | 384 |     0,                                  /* tp_itemsize */ | 
 | 385 |     /* methods */ | 
 | 386 |     (destructor)keyobject_dealloc,      /* tp_dealloc */ | 
 | 387 |     0,                                  /* tp_print */ | 
 | 388 |     0,                                  /* tp_getattr */ | 
 | 389 |     0,                                  /* tp_setattr */ | 
 | 390 |     0,                                  /* tp_reserved */ | 
 | 391 |     0,                                  /* tp_repr */ | 
 | 392 |     0,                                  /* tp_as_number */ | 
 | 393 |     0,                                  /* tp_as_sequence */ | 
 | 394 |     0,                                  /* tp_as_mapping */ | 
 | 395 |     0,                                  /* tp_hash */ | 
 | 396 |     (ternaryfunc)keyobject_call,        /* tp_call */ | 
 | 397 |     0,                                  /* tp_str */ | 
 | 398 |     PyObject_GenericGetAttr,            /* tp_getattro */ | 
 | 399 |     0,                                  /* tp_setattro */ | 
 | 400 |     0,                                  /* tp_as_buffer */ | 
 | 401 |     Py_TPFLAGS_DEFAULT,                 /* tp_flags */ | 
 | 402 |     0,                                  /* tp_doc */ | 
 | 403 |     (traverseproc)keyobject_traverse,   /* tp_traverse */ | 
| Benjamin Peterson | 3bd9729 | 2011-04-05 17:25:14 -0500 | [diff] [blame] | 404 |     (inquiry)keyobject_clear,           /* tp_clear */ | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 405 |     keyobject_richcompare,              /* tp_richcompare */ | 
 | 406 |     0,                                  /* tp_weaklistoffset */ | 
 | 407 |     0,                                  /* tp_iter */ | 
 | 408 |     0,                                  /* tp_iternext */ | 
 | 409 |     0,                                  /* tp_methods */ | 
 | 410 |     keyobject_members,                  /* tp_members */ | 
 | 411 |     0,                                  /* tp_getset */ | 
 | 412 | }; | 
 | 413 |  | 
 | 414 | static PyObject * | 
 | 415 | keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds) | 
 | 416 | { | 
 | 417 |     PyObject *object; | 
 | 418 |     keyobject *result; | 
 | 419 |     static char *kwargs[] = {"obj", NULL}; | 
 | 420 |  | 
 | 421 |     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object)) | 
 | 422 |         return NULL; | 
 | 423 |     result = PyObject_New(keyobject, &keyobject_type); | 
 | 424 |     if (!result) | 
 | 425 |         return NULL; | 
 | 426 |     Py_INCREF(ko->cmp); | 
 | 427 |     result->cmp = ko->cmp; | 
 | 428 |     Py_INCREF(object); | 
 | 429 |     result->object = object; | 
 | 430 |     return (PyObject *)result; | 
 | 431 | } | 
 | 432 |  | 
 | 433 | static PyObject * | 
 | 434 | keyobject_richcompare(PyObject *ko, PyObject *other, int op) | 
 | 435 | { | 
 | 436 |     PyObject *res; | 
 | 437 |     PyObject *args; | 
 | 438 |     PyObject *x; | 
 | 439 |     PyObject *y; | 
 | 440 |     PyObject *compare; | 
 | 441 |     PyObject *answer; | 
 | 442 |     static PyObject *zero; | 
 | 443 |  | 
 | 444 |     if (zero == NULL) { | 
 | 445 |         zero = PyLong_FromLong(0); | 
 | 446 |         if (!zero) | 
 | 447 |             return NULL; | 
 | 448 |     } | 
 | 449 |  | 
 | 450 |     if (Py_TYPE(other) != &keyobject_type){ | 
 | 451 |         PyErr_Format(PyExc_TypeError, "other argument must be K instance"); | 
 | 452 |         return NULL; | 
 | 453 |     } | 
 | 454 |     compare = ((keyobject *) ko)->cmp; | 
 | 455 |     assert(compare != NULL); | 
 | 456 |     x = ((keyobject *) ko)->object; | 
 | 457 |     y = ((keyobject *) other)->object; | 
 | 458 |     if (!x || !y){ | 
 | 459 |         PyErr_Format(PyExc_AttributeError, "object"); | 
 | 460 |         return NULL; | 
 | 461 |     } | 
 | 462 |  | 
 | 463 |     /* Call the user's comparison function and translate the 3-way | 
 | 464 |      * result into true or false (or error). | 
 | 465 |      */ | 
 | 466 |     args = PyTuple_New(2); | 
 | 467 |     if (args == NULL) | 
 | 468 |         return NULL; | 
 | 469 |     Py_INCREF(x); | 
 | 470 |     Py_INCREF(y); | 
 | 471 |     PyTuple_SET_ITEM(args, 0, x); | 
 | 472 |     PyTuple_SET_ITEM(args, 1, y); | 
 | 473 |     res = PyObject_Call(compare, args, NULL); | 
 | 474 |     Py_DECREF(args); | 
 | 475 |     if (res == NULL) | 
 | 476 |         return NULL; | 
 | 477 |     answer = PyObject_RichCompare(res, zero, op); | 
 | 478 |     Py_DECREF(res); | 
 | 479 |     return answer; | 
 | 480 | } | 
 | 481 |  | 
 | 482 | static PyObject * | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 483 | functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds) | 
 | 484 | { | 
 | 485 |     PyObject *cmp; | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 486 |     static char *kwargs[] = {"mycmp", NULL}; | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 487 |     keyobject *object; | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 488 |  | 
 | 489 |     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp)) | 
 | 490 |         return NULL; | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 491 |     object = PyObject_New(keyobject, &keyobject_type); | 
| Raymond Hettinger | 7ab9e22 | 2011-04-05 02:33:54 -0700 | [diff] [blame] | 492 |     if (!object) | 
 | 493 |         return NULL; | 
 | 494 |     Py_INCREF(cmp); | 
 | 495 |     object->cmp = cmp; | 
 | 496 |     object->object = NULL; | 
 | 497 |     return (PyObject *)object; | 
 | 498 | } | 
 | 499 |  | 
 | 500 | PyDoc_STRVAR(functools_cmp_to_key_doc, | 
 | 501 | "Convert a cmp= function into a key= function."); | 
 | 502 |  | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 503 | /* reduce (used to be a builtin) ********************************************/ | 
 | 504 |  | 
 | 505 | static PyObject * | 
 | 506 | functools_reduce(PyObject *self, PyObject *args) | 
 | 507 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 508 |     PyObject *seq, *func, *result = NULL, *it; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 509 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 510 |     if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result)) | 
 | 511 |         return NULL; | 
 | 512 |     if (result != NULL) | 
 | 513 |         Py_INCREF(result); | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 514 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 515 |     it = PyObject_GetIter(seq); | 
 | 516 |     if (it == NULL) { | 
| Alexander Belopolsky | e29e6bf | 2010-08-16 18:55:46 +0000 | [diff] [blame] | 517 |         if (PyErr_ExceptionMatches(PyExc_TypeError)) | 
 | 518 |             PyErr_SetString(PyExc_TypeError, | 
 | 519 |                             "reduce() arg 2 must support iteration"); | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 520 |         Py_XDECREF(result); | 
 | 521 |         return NULL; | 
 | 522 |     } | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 523 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 524 |     if ((args = PyTuple_New(2)) == NULL) | 
 | 525 |         goto Fail; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 526 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 527 |     for (;;) { | 
 | 528 |         PyObject *op2; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 529 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 530 |         if (args->ob_refcnt > 1) { | 
 | 531 |             Py_DECREF(args); | 
 | 532 |             if ((args = PyTuple_New(2)) == NULL) | 
 | 533 |                 goto Fail; | 
 | 534 |         } | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 535 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 536 |         op2 = PyIter_Next(it); | 
 | 537 |         if (op2 == NULL) { | 
 | 538 |             if (PyErr_Occurred()) | 
 | 539 |                 goto Fail; | 
 | 540 |             break; | 
 | 541 |         } | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 542 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 543 |         if (result == NULL) | 
 | 544 |             result = op2; | 
 | 545 |         else { | 
 | 546 |             PyTuple_SetItem(args, 0, result); | 
 | 547 |             PyTuple_SetItem(args, 1, op2); | 
 | 548 |             if ((result = PyEval_CallObject(func, args)) == NULL) | 
 | 549 |                 goto Fail; | 
 | 550 |         } | 
 | 551 |     } | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 552 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 553 |     Py_DECREF(args); | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 554 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 555 |     if (result == NULL) | 
 | 556 |         PyErr_SetString(PyExc_TypeError, | 
 | 557 |                    "reduce() of empty sequence with no initial value"); | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 558 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 559 |     Py_DECREF(it); | 
 | 560 |     return result; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 561 |  | 
 | 562 | Fail: | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 563 |     Py_XDECREF(args); | 
 | 564 |     Py_XDECREF(result); | 
 | 565 |     Py_DECREF(it); | 
 | 566 |     return NULL; | 
| Guido van Rossum | 0919a1a | 2006-08-26 20:49:04 +0000 | [diff] [blame] | 567 | } | 
 | 568 |  | 
 | 569 | PyDoc_STRVAR(functools_reduce_doc, | 
 | 570 | "reduce(function, sequence[, initial]) -> value\n\ | 
 | 571 | \n\ | 
 | 572 | Apply a function of two arguments cumulatively to the items of a sequence,\n\ | 
 | 573 | from left to right, so as to reduce the sequence to a single value.\n\ | 
 | 574 | For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\ | 
 | 575 | ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items\n\ | 
 | 576 | of the sequence in the calculation, and serves as a default when the\n\ | 
 | 577 | sequence is empty."); | 
 | 578 |  | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 579 | /* module level code ********************************************************/ | 
 | 580 |  | 
 | 581 | PyDoc_STRVAR(module_doc, | 
| Thomas Wouters | 4d70c3d | 2006-06-08 14:42:34 +0000 | [diff] [blame] | 582 | "Tools that operate on functions."); | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 583 |  | 
 | 584 | static PyMethodDef module_methods[] = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 585 |     {"reduce",          functools_reduce,     METH_VARARGS, functools_reduce_doc}, | 
| Victor Stinner | 446c8d5 | 2011-04-05 12:21:35 +0200 | [diff] [blame] | 586 |     {"cmp_to_key",      (PyCFunction)functools_cmp_to_key, | 
 | 587 |      METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc}, | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 588 |     {NULL,              NULL}           /* sentinel */ | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 589 | }; | 
 | 590 |  | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 591 |  | 
 | 592 | static struct PyModuleDef _functoolsmodule = { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 593 |     PyModuleDef_HEAD_INIT, | 
 | 594 |     "_functools", | 
 | 595 |     module_doc, | 
 | 596 |     -1, | 
 | 597 |     module_methods, | 
 | 598 |     NULL, | 
 | 599 |     NULL, | 
 | 600 |     NULL, | 
 | 601 |     NULL | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 602 | }; | 
 | 603 |  | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 604 | PyMODINIT_FUNC | 
| Martin v. Löwis | 1a21451 | 2008-06-11 05:26:20 +0000 | [diff] [blame] | 605 | PyInit__functools(void) | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 606 | { | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 607 |     int i; | 
 | 608 |     PyObject *m; | 
 | 609 |     char *name; | 
 | 610 |     PyTypeObject *typelist[] = { | 
 | 611 |         &partial_type, | 
 | 612 |         NULL | 
 | 613 |     }; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 614 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 615 |     m = PyModule_Create(&_functoolsmodule); | 
 | 616 |     if (m == NULL) | 
 | 617 |         return NULL; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 618 |  | 
| Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 619 |     for (i=0 ; typelist[i] != NULL ; i++) { | 
 | 620 |         if (PyType_Ready(typelist[i]) < 0) { | 
 | 621 |             Py_DECREF(m); | 
 | 622 |             return NULL; | 
 | 623 |         } | 
 | 624 |         name = strchr(typelist[i]->tp_name, '.'); | 
 | 625 |         assert (name != NULL); | 
 | 626 |         Py_INCREF(typelist[i]); | 
 | 627 |         PyModule_AddObject(m, name+1, (PyObject *)typelist[i]); | 
 | 628 |     } | 
 | 629 |     return m; | 
| Raymond Hettinger | 9c323f8 | 2005-02-28 19:39:44 +0000 | [diff] [blame] | 630 | } |