blob: 620570808cdaa1fc9e788b60e6940d78c042dd82 [file] [log] [blame]
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001
2#include "Python.h"
3#include "structmember.h"
4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00005/* _functools module written and maintained
Raymond Hettinger9c323f82005-02-28 19:39:44 +00006 by Hye-Shik Chang <perky@FreeBSD.org>
7 with adaptations by Raymond Hettinger <python@rcn.com>
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00008 Copyright (c) 2004, 2005, 2006 Python Software Foundation.
Raymond Hettinger9c323f82005-02-28 19:39:44 +00009 All rights reserved.
10*/
11
12/* partial object **********************************************************/
13
14typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000015 PyObject_HEAD
16 PyObject *fn;
17 PyObject *args;
18 PyObject *kw;
19 PyObject *dict;
20 PyObject *weakreflist; /* List of weak references */
Raymond Hettinger9c323f82005-02-28 19:39:44 +000021} partialobject;
22
23static PyTypeObject partial_type;
24
25static PyObject *
26partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
27{
Alexander Belopolskye49af342015-03-01 15:08:17 -050028 PyObject *func, *pargs, *nargs, *pkw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000029 partialobject *pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000030
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000031 if (PyTuple_GET_SIZE(args) < 1) {
32 PyErr_SetString(PyExc_TypeError,
33 "type 'partial' takes at least one argument");
34 return NULL;
35 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000036
Serhiy Storchaka38741282016-02-02 18:45:17 +020037 pargs = pkw = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000038 func = PyTuple_GET_ITEM(args, 0);
Alexander Belopolskye49af342015-03-01 15:08:17 -050039 if (Py_TYPE(func) == &partial_type && type == &partial_type) {
40 partialobject *part = (partialobject *)func;
41 if (part->dict == NULL) {
42 pargs = part->args;
43 pkw = part->kw;
44 func = part->fn;
Serhiy Storchaka38741282016-02-02 18:45:17 +020045 assert(PyTuple_Check(pargs));
46 assert(PyDict_Check(pkw));
Alexander Belopolskye49af342015-03-01 15:08:17 -050047 }
48 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000049 if (!PyCallable_Check(func)) {
50 PyErr_SetString(PyExc_TypeError,
51 "the first argument must be callable");
52 return NULL;
53 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000054
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000055 /* create partialobject structure */
56 pto = (partialobject *)type->tp_alloc(type, 0);
57 if (pto == NULL)
58 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000059
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 pto->fn = func;
61 Py_INCREF(func);
Alexander Belopolskye49af342015-03-01 15:08:17 -050062
63 nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
64 if (nargs == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000065 Py_DECREF(pto);
66 return NULL;
67 }
Serhiy Storchaka38741282016-02-02 18:45:17 +020068 if (pargs == NULL || PyTuple_GET_SIZE(pargs) == 0) {
Alexander Belopolskye49af342015-03-01 15:08:17 -050069 pto->args = nargs;
70 Py_INCREF(nargs);
71 }
72 else if (PyTuple_GET_SIZE(nargs) == 0) {
73 pto->args = pargs;
74 Py_INCREF(pargs);
75 }
76 else {
77 pto->args = PySequence_Concat(pargs, nargs);
78 if (pto->args == NULL) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020079 Py_DECREF(nargs);
Alexander Belopolskye49af342015-03-01 15:08:17 -050080 Py_DECREF(pto);
81 return NULL;
82 }
Serhiy Storchaka38741282016-02-02 18:45:17 +020083 assert(PyTuple_Check(pto->args));
Alexander Belopolskye49af342015-03-01 15:08:17 -050084 }
85 Py_DECREF(nargs);
86
Serhiy Storchaka38741282016-02-02 18:45:17 +020087 if (pkw == NULL || PyDict_Size(pkw) == 0) {
88 if (kw == NULL) {
89 pto->kw = PyDict_New();
Alexander Belopolskye49af342015-03-01 15:08:17 -050090 }
91 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +020092 Py_INCREF(kw);
93 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000094 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050095 }
96 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +020097 pto->kw = PyDict_Copy(pkw);
98 if (kw != NULL && pto->kw != NULL) {
99 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -0400100 Py_DECREF(pto);
101 return NULL;
102 }
103 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200105 if (pto->kw == NULL) {
106 Py_DECREF(pto);
107 return NULL;
108 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000109
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 return (PyObject *)pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000111}
112
113static void
114partial_dealloc(partialobject *pto)
115{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000116 PyObject_GC_UnTrack(pto);
117 if (pto->weakreflist != NULL)
118 PyObject_ClearWeakRefs((PyObject *) pto);
119 Py_XDECREF(pto->fn);
120 Py_XDECREF(pto->args);
121 Py_XDECREF(pto->kw);
122 Py_XDECREF(pto->dict);
123 Py_TYPE(pto)->tp_free(pto);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000124}
125
126static PyObject *
127partial_call(partialobject *pto, PyObject *args, PyObject *kw)
128{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129 PyObject *ret;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200130 PyObject *argappl, *kwappl;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000131
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 assert (PyCallable_Check(pto->fn));
133 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200134 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000135
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 if (PyTuple_GET_SIZE(pto->args) == 0) {
137 argappl = args;
138 Py_INCREF(args);
139 } else if (PyTuple_GET_SIZE(args) == 0) {
140 argappl = pto->args;
141 Py_INCREF(pto->args);
142 } else {
143 argappl = PySequence_Concat(pto->args, args);
144 if (argappl == NULL)
145 return NULL;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200146 assert(PyTuple_Check(argappl));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000148
Serhiy Storchaka38741282016-02-02 18:45:17 +0200149 if (PyDict_Size(pto->kw) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000150 kwappl = kw;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200151 Py_XINCREF(kwappl);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000152 } else {
153 kwappl = PyDict_Copy(pto->kw);
154 if (kwappl == NULL) {
155 Py_DECREF(argappl);
156 return NULL;
157 }
158 if (kw != NULL) {
159 if (PyDict_Merge(kwappl, kw, 1) != 0) {
160 Py_DECREF(argappl);
161 Py_DECREF(kwappl);
162 return NULL;
163 }
164 }
165 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000166
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 ret = PyObject_Call(pto->fn, argappl, kwappl);
168 Py_DECREF(argappl);
169 Py_XDECREF(kwappl);
170 return ret;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000171}
172
173static int
174partial_traverse(partialobject *pto, visitproc visit, void *arg)
175{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 Py_VISIT(pto->fn);
177 Py_VISIT(pto->args);
178 Py_VISIT(pto->kw);
179 Py_VISIT(pto->dict);
180 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000181}
182
183PyDoc_STRVAR(partial_doc,
184"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000185 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000186
187#define OFF(x) offsetof(partialobject, x)
188static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 {"func", T_OBJECT, OFF(fn), READONLY,
190 "function object to use in future partial calls"},
191 {"args", T_OBJECT, OFF(args), READONLY,
192 "tuple of arguments to future partial calls"},
193 {"keywords", T_OBJECT, OFF(kw), READONLY,
194 "dictionary of keyword arguments to future partial calls"},
195 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000196};
197
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000198static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500199 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000200 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000201};
202
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000203static PyObject *
204partial_repr(partialobject *pto)
205{
206 PyObject *result;
207 PyObject *arglist;
208 PyObject *tmp;
209 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200210 PyObject *key, *value;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000211
212 arglist = PyUnicode_FromString("");
213 if (arglist == NULL) {
214 return NULL;
215 }
216 /* Pack positional arguments */
217 assert (PyTuple_Check(pto->args));
218 n = PyTuple_GET_SIZE(pto->args);
219 for (i = 0; i < n; i++) {
220 tmp = PyUnicode_FromFormat("%U, %R", arglist,
221 PyTuple_GET_ITEM(pto->args, i));
222 Py_DECREF(arglist);
223 if (tmp == NULL)
224 return NULL;
225 arglist = tmp;
226 }
227 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200228 assert (PyDict_Check(pto->kw));
229 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
230 tmp = PyUnicode_FromFormat("%U, %U=%R", arglist,
231 key, value);
232 Py_DECREF(arglist);
233 if (tmp == NULL)
234 return NULL;
235 arglist = tmp;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000236 }
237 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
238 pto->fn, arglist);
239 Py_DECREF(arglist);
240 return result;
241}
242
Jack Diederiche0cbd692009-04-01 04:27:09 +0000243/* Pickle strategy:
244 __reduce__ by itself doesn't support getting kwargs in the unpickle
245 operation so we define a __setstate__ that replaces all the information
246 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200247 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000248 */
249
Antoine Pitrou69f71142009-05-24 21:25:49 +0000250static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000251partial_reduce(partialobject *pto, PyObject *unused)
252{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
254 pto->args, pto->kw,
255 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000256}
257
Antoine Pitrou69f71142009-05-24 21:25:49 +0000258static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200259partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000260{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000261 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200262
263 if (!PyTuple_Check(state) ||
264 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
265 !PyCallable_Check(fn) ||
266 !PyTuple_Check(fnargs) ||
267 (kw != Py_None && !PyDict_Check(kw)))
268 {
269 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000271 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200272
273 if(!PyTuple_CheckExact(fnargs))
274 fnargs = PySequence_Tuple(fnargs);
275 else
276 Py_INCREF(fnargs);
277 if (fnargs == NULL)
278 return NULL;
279
280 if (kw == Py_None)
281 kw = PyDict_New();
282 else if(!PyDict_CheckExact(kw))
283 kw = PyDict_Copy(kw);
284 else
285 Py_INCREF(kw);
286 if (kw == NULL) {
287 Py_DECREF(fnargs);
288 return NULL;
289 }
290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 Py_INCREF(fn);
Serhiy Storchaka38741282016-02-02 18:45:17 +0200292 if (dict == Py_None)
293 dict = NULL;
294 else
295 Py_INCREF(dict);
296
Serhiy Storchaka48842712016-04-06 09:45:48 +0300297 Py_XSETREF(pto->fn, fn);
298 Py_XSETREF(pto->args, fnargs);
299 Py_XSETREF(pto->kw, kw);
300 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000301 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000302}
303
304static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000305 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200306 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000307 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000308};
309
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000310static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000311 PyVarObject_HEAD_INIT(NULL, 0)
312 "functools.partial", /* tp_name */
313 sizeof(partialobject), /* tp_basicsize */
314 0, /* tp_itemsize */
315 /* methods */
316 (destructor)partial_dealloc, /* tp_dealloc */
317 0, /* tp_print */
318 0, /* tp_getattr */
319 0, /* tp_setattr */
320 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000321 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 0, /* tp_as_number */
323 0, /* tp_as_sequence */
324 0, /* tp_as_mapping */
325 0, /* tp_hash */
326 (ternaryfunc)partial_call, /* tp_call */
327 0, /* tp_str */
328 PyObject_GenericGetAttr, /* tp_getattro */
329 PyObject_GenericSetAttr, /* tp_setattro */
330 0, /* tp_as_buffer */
331 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
332 Py_TPFLAGS_BASETYPE, /* tp_flags */
333 partial_doc, /* tp_doc */
334 (traverseproc)partial_traverse, /* tp_traverse */
335 0, /* tp_clear */
336 0, /* tp_richcompare */
337 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
338 0, /* tp_iter */
339 0, /* tp_iternext */
340 partial_methods, /* tp_methods */
341 partial_memberlist, /* tp_members */
342 partial_getsetlist, /* tp_getset */
343 0, /* tp_base */
344 0, /* tp_dict */
345 0, /* tp_descr_get */
346 0, /* tp_descr_set */
347 offsetof(partialobject, dict), /* tp_dictoffset */
348 0, /* tp_init */
349 0, /* tp_alloc */
350 partial_new, /* tp_new */
351 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000352};
353
354
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700355/* cmp_to_key ***************************************************************/
356
357typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200358 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700359 PyObject *cmp;
360 PyObject *object;
361} keyobject;
362
363static void
364keyobject_dealloc(keyobject *ko)
365{
366 Py_DECREF(ko->cmp);
367 Py_XDECREF(ko->object);
368 PyObject_FREE(ko);
369}
370
371static int
372keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
373{
374 Py_VISIT(ko->cmp);
375 if (ko->object)
376 Py_VISIT(ko->object);
377 return 0;
378}
379
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500380static int
381keyobject_clear(keyobject *ko)
382{
383 Py_CLEAR(ko->cmp);
384 if (ko->object)
385 Py_CLEAR(ko->object);
386 return 0;
387}
388
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700389static PyMemberDef keyobject_members[] = {
390 {"obj", T_OBJECT,
391 offsetof(keyobject, object), 0,
392 PyDoc_STR("Value wrapped by a key function.")},
393 {NULL}
394};
395
396static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700397keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700398
399static PyObject *
400keyobject_richcompare(PyObject *ko, PyObject *other, int op);
401
402static PyTypeObject keyobject_type = {
403 PyVarObject_HEAD_INIT(&PyType_Type, 0)
404 "functools.KeyWrapper", /* tp_name */
405 sizeof(keyobject), /* tp_basicsize */
406 0, /* tp_itemsize */
407 /* methods */
408 (destructor)keyobject_dealloc, /* tp_dealloc */
409 0, /* tp_print */
410 0, /* tp_getattr */
411 0, /* tp_setattr */
412 0, /* tp_reserved */
413 0, /* tp_repr */
414 0, /* tp_as_number */
415 0, /* tp_as_sequence */
416 0, /* tp_as_mapping */
417 0, /* tp_hash */
418 (ternaryfunc)keyobject_call, /* tp_call */
419 0, /* tp_str */
420 PyObject_GenericGetAttr, /* tp_getattro */
421 0, /* tp_setattro */
422 0, /* tp_as_buffer */
423 Py_TPFLAGS_DEFAULT, /* tp_flags */
424 0, /* tp_doc */
425 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500426 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700427 keyobject_richcompare, /* tp_richcompare */
428 0, /* tp_weaklistoffset */
429 0, /* tp_iter */
430 0, /* tp_iternext */
431 0, /* tp_methods */
432 keyobject_members, /* tp_members */
433 0, /* tp_getset */
434};
435
436static PyObject *
437keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
438{
439 PyObject *object;
440 keyobject *result;
441 static char *kwargs[] = {"obj", NULL};
442
443 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
444 return NULL;
445 result = PyObject_New(keyobject, &keyobject_type);
446 if (!result)
447 return NULL;
448 Py_INCREF(ko->cmp);
449 result->cmp = ko->cmp;
450 Py_INCREF(object);
451 result->object = object;
452 return (PyObject *)result;
453}
454
455static PyObject *
456keyobject_richcompare(PyObject *ko, PyObject *other, int op)
457{
458 PyObject *res;
459 PyObject *args;
460 PyObject *x;
461 PyObject *y;
462 PyObject *compare;
463 PyObject *answer;
464 static PyObject *zero;
465
466 if (zero == NULL) {
467 zero = PyLong_FromLong(0);
468 if (!zero)
469 return NULL;
470 }
471
472 if (Py_TYPE(other) != &keyobject_type){
473 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
474 return NULL;
475 }
476 compare = ((keyobject *) ko)->cmp;
477 assert(compare != NULL);
478 x = ((keyobject *) ko)->object;
479 y = ((keyobject *) other)->object;
480 if (!x || !y){
481 PyErr_Format(PyExc_AttributeError, "object");
482 return NULL;
483 }
484
485 /* Call the user's comparison function and translate the 3-way
486 * result into true or false (or error).
487 */
488 args = PyTuple_New(2);
489 if (args == NULL)
490 return NULL;
491 Py_INCREF(x);
492 Py_INCREF(y);
493 PyTuple_SET_ITEM(args, 0, x);
494 PyTuple_SET_ITEM(args, 1, y);
495 res = PyObject_Call(compare, args, NULL);
496 Py_DECREF(args);
497 if (res == NULL)
498 return NULL;
499 answer = PyObject_RichCompare(res, zero, op);
500 Py_DECREF(res);
501 return answer;
502}
503
504static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200505functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
506{
507 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700508 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200509 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700510
511 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
512 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200513 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700514 if (!object)
515 return NULL;
516 Py_INCREF(cmp);
517 object->cmp = cmp;
518 object->object = NULL;
519 return (PyObject *)object;
520}
521
522PyDoc_STRVAR(functools_cmp_to_key_doc,
523"Convert a cmp= function into a key= function.");
524
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000525/* reduce (used to be a builtin) ********************************************/
526
527static PyObject *
528functools_reduce(PyObject *self, PyObject *args)
529{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000530 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000531
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000532 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
533 return NULL;
534 if (result != NULL)
535 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000536
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000537 it = PyObject_GetIter(seq);
538 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000539 if (PyErr_ExceptionMatches(PyExc_TypeError))
540 PyErr_SetString(PyExc_TypeError,
541 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000542 Py_XDECREF(result);
543 return NULL;
544 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000545
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000546 if ((args = PyTuple_New(2)) == NULL)
547 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000548
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000549 for (;;) {
550 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000551
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000552 if (args->ob_refcnt > 1) {
553 Py_DECREF(args);
554 if ((args = PyTuple_New(2)) == NULL)
555 goto Fail;
556 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000557
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000558 op2 = PyIter_Next(it);
559 if (op2 == NULL) {
560 if (PyErr_Occurred())
561 goto Fail;
562 break;
563 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000564
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000565 if (result == NULL)
566 result = op2;
567 else {
568 PyTuple_SetItem(args, 0, result);
569 PyTuple_SetItem(args, 1, op2);
570 if ((result = PyEval_CallObject(func, args)) == NULL)
571 goto Fail;
572 }
573 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000574
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000576
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000577 if (result == NULL)
578 PyErr_SetString(PyExc_TypeError,
579 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000580
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000581 Py_DECREF(it);
582 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000583
584Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000585 Py_XDECREF(args);
586 Py_XDECREF(result);
587 Py_DECREF(it);
588 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000589}
590
591PyDoc_STRVAR(functools_reduce_doc,
592"reduce(function, sequence[, initial]) -> value\n\
593\n\
594Apply a function of two arguments cumulatively to the items of a sequence,\n\
595from left to right, so as to reduce the sequence to a single value.\n\
596For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
597((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
598of the sequence in the calculation, and serves as a default when the\n\
599sequence is empty.");
600
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300601/* lru_cache object **********************************************************/
602
603/* this object is used delimit args and keywords in the cache keys */
604static PyObject *kwd_mark = NULL;
605
606struct lru_list_elem;
607struct lru_cache_object;
608
609typedef struct lru_list_elem {
610 PyObject_HEAD
611 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300612 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300613 PyObject *key, *result;
614} lru_list_elem;
615
616static void
617lru_list_elem_dealloc(lru_list_elem *link)
618{
619 _PyObject_GC_UNTRACK(link);
620 Py_XDECREF(link->key);
621 Py_XDECREF(link->result);
622 PyObject_GC_Del(link);
623}
624
625static int
626lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
627{
628 Py_VISIT(link->key);
629 Py_VISIT(link->result);
630 return 0;
631}
632
633static int
634lru_list_elem_clear(lru_list_elem *link)
635{
636 Py_CLEAR(link->key);
637 Py_CLEAR(link->result);
638 return 0;
639}
640
641static PyTypeObject lru_list_elem_type = {
642 PyVarObject_HEAD_INIT(&PyType_Type, 0)
643 "functools._lru_list_elem", /* tp_name */
644 sizeof(lru_list_elem), /* tp_basicsize */
645 0, /* tp_itemsize */
646 /* methods */
647 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
648 0, /* tp_print */
649 0, /* tp_getattr */
650 0, /* tp_setattr */
651 0, /* tp_reserved */
652 0, /* tp_repr */
653 0, /* tp_as_number */
654 0, /* tp_as_sequence */
655 0, /* tp_as_mapping */
656 0, /* tp_hash */
657 0, /* tp_call */
658 0, /* tp_str */
659 0, /* tp_getattro */
660 0, /* tp_setattro */
661 0, /* tp_as_buffer */
662 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
663 0, /* tp_doc */
664 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
665 (inquiry)lru_list_elem_clear, /* tp_clear */
666};
667
668
669typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
670
671typedef struct lru_cache_object {
672 lru_list_elem root; /* includes PyObject_HEAD */
673 Py_ssize_t maxsize;
674 PyObject *maxsize_O;
675 PyObject *func;
676 lru_cache_ternaryfunc wrapper;
677 PyObject *cache;
678 PyObject *cache_info_type;
679 Py_ssize_t misses, hits;
680 int typed;
681 PyObject *dict;
682 int full;
683} lru_cache_object;
684
685static PyTypeObject lru_cache_type;
686
687static PyObject *
688lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
689{
690 PyObject *key, *sorted_items;
691 Py_ssize_t key_size, pos, key_pos;
692
693 /* short path, key will match args anyway, which is a tuple */
694 if (!typed && !kwds) {
695 Py_INCREF(args);
696 return args;
697 }
698
699 if (kwds && PyDict_Size(kwds) > 0) {
700 sorted_items = PyDict_Items(kwds);
701 if (!sorted_items)
702 return NULL;
703 if (PyList_Sort(sorted_items) < 0) {
704 Py_DECREF(sorted_items);
705 return NULL;
706 }
707 } else
708 sorted_items = NULL;
709
710 key_size = PyTuple_GET_SIZE(args);
711 if (sorted_items)
712 key_size += PyList_GET_SIZE(sorted_items);
713 if (typed)
714 key_size *= 2;
715 if (sorted_items)
716 key_size++;
717
718 key = PyTuple_New(key_size);
719 if (key == NULL)
720 goto done;
721
722 key_pos = 0;
723 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
724 PyObject *item = PyTuple_GET_ITEM(args, pos);
725 Py_INCREF(item);
726 PyTuple_SET_ITEM(key, key_pos++, item);
727 }
728 if (sorted_items) {
729 Py_INCREF(kwd_mark);
730 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
731 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
732 PyObject *item = PyList_GET_ITEM(sorted_items, pos);
733 Py_INCREF(item);
734 PyTuple_SET_ITEM(key, key_pos++, item);
735 }
736 }
737 if (typed) {
738 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
739 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
740 Py_INCREF(item);
741 PyTuple_SET_ITEM(key, key_pos++, item);
742 }
743 if (sorted_items) {
744 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
745 PyObject *tp_items = PyList_GET_ITEM(sorted_items, pos);
746 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(tp_items, 1));
747 Py_INCREF(item);
748 PyTuple_SET_ITEM(key, key_pos++, item);
749 }
750 }
751 }
752 assert(key_pos == key_size);
753
754done:
755 if (sorted_items)
756 Py_DECREF(sorted_items);
757 return key;
758}
759
760static PyObject *
761uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
762{
763 PyObject *result = PyObject_Call(self->func, args, kwds);
764 if (!result)
765 return NULL;
766 self->misses++;
767 return result;
768}
769
770static PyObject *
771infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
772{
773 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300774 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300775 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
776 if (!key)
777 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300778 hash = PyObject_Hash(key);
779 if (hash == -1)
780 return NULL;
781 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300782 if (result) {
783 Py_INCREF(result);
784 self->hits++;
785 Py_DECREF(key);
786 return result;
787 }
788 if (PyErr_Occurred()) {
789 Py_DECREF(key);
790 return NULL;
791 }
792 result = PyObject_Call(self->func, args, kwds);
793 if (!result) {
794 Py_DECREF(key);
795 return NULL;
796 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300797 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300798 Py_DECREF(result);
799 Py_DECREF(key);
800 return NULL;
801 }
802 Py_DECREF(key);
803 self->misses++;
804 return result;
805}
806
807static void
808lru_cache_extricate_link(lru_list_elem *link)
809{
810 link->prev->next = link->next;
811 link->next->prev = link->prev;
812}
813
814static void
815lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
816{
817 lru_list_elem *root = &self->root;
818 lru_list_elem *last = root->prev;
819 last->next = root->prev = link;
820 link->prev = last;
821 link->next = root;
822}
823
824static PyObject *
825bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
826{
827 lru_list_elem *link;
828 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300829 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300830
831 key = lru_cache_make_key(args, kwds, self->typed);
832 if (!key)
833 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300834 hash = PyObject_Hash(key);
835 if (hash == -1)
836 return NULL;
837 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300838 if (link) {
839 lru_cache_extricate_link(link);
840 lru_cache_append_link(self, link);
841 self->hits++;
842 result = link->result;
843 Py_INCREF(result);
844 Py_DECREF(key);
845 return result;
846 }
847 if (PyErr_Occurred()) {
848 Py_DECREF(key);
849 return NULL;
850 }
851 result = PyObject_Call(self->func, args, kwds);
852 if (!result) {
853 Py_DECREF(key);
854 return NULL;
855 }
856 if (self->full && self->root.next != &self->root) {
857 /* Use the oldest item to store the new key and result. */
858 PyObject *oldkey, *oldresult;
859 /* Extricate the oldest item. */
860 link = self->root.next;
861 lru_cache_extricate_link(link);
862 /* Remove it from the cache.
863 The cache dict holds one reference to the link,
864 and the linked list holds yet one reference to it. */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300865 if (_PyDict_DelItem_KnownHash(self->cache, link->key,
866 link->hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300867 lru_cache_append_link(self, link);
868 Py_DECREF(key);
869 Py_DECREF(result);
870 return NULL;
871 }
872 /* Keep a reference to the old key and old result to
873 prevent their ref counts from going to zero during the
874 update. That will prevent potentially arbitrary object
875 clean-up code (i.e. __del__) from running while we're
876 still adjusting the links. */
877 oldkey = link->key;
878 oldresult = link->result;
879
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300880 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300881 link->key = key;
882 link->result = result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300883 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
884 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300885 Py_DECREF(link);
886 Py_DECREF(oldkey);
887 Py_DECREF(oldresult);
888 return NULL;
889 }
890 lru_cache_append_link(self, link);
891 Py_INCREF(result); /* for return */
892 Py_DECREF(oldkey);
893 Py_DECREF(oldresult);
894 } else {
895 /* Put result in a new link at the front of the queue. */
896 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
897 &lru_list_elem_type);
898 if (link == NULL) {
899 Py_DECREF(key);
900 Py_DECREF(result);
901 return NULL;
902 }
903
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300904 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300905 link->key = key;
906 link->result = result;
907 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300908 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
909 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300910 Py_DECREF(link);
911 return NULL;
912 }
913 lru_cache_append_link(self, link);
914 Py_INCREF(result); /* for return */
915 self->full = (PyDict_Size(self->cache) >= self->maxsize);
916 }
917 self->misses++;
918 return result;
919}
920
921static PyObject *
922lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
923{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300924 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300925 int typed;
926 lru_cache_object *obj;
927 Py_ssize_t maxsize;
928 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
929 static char *keywords[] = {"user_function", "maxsize", "typed",
930 "cache_info_type", NULL};
931
932 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
933 &func, &maxsize_O, &typed,
934 &cache_info_type)) {
935 return NULL;
936 }
937
938 if (!PyCallable_Check(func)) {
939 PyErr_SetString(PyExc_TypeError,
940 "the first argument must be callable");
941 return NULL;
942 }
943
944 /* select the caching function, and make/inc maxsize_O */
945 if (maxsize_O == Py_None) {
946 wrapper = infinite_lru_cache_wrapper;
947 /* use this only to initialize lru_cache_object attribute maxsize */
948 maxsize = -1;
949 } else if (PyIndex_Check(maxsize_O)) {
950 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
951 if (maxsize == -1 && PyErr_Occurred())
952 return NULL;
953 if (maxsize == 0)
954 wrapper = uncached_lru_cache_wrapper;
955 else
956 wrapper = bounded_lru_cache_wrapper;
957 } else {
958 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
959 return NULL;
960 }
961
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300962 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300963 return NULL;
964
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300965 obj = (lru_cache_object *)type->tp_alloc(type, 0);
966 if (obj == NULL) {
967 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300968 return NULL;
969 }
970
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300971 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300972 obj->root.prev = &obj->root;
973 obj->root.next = &obj->root;
974 obj->maxsize = maxsize;
975 Py_INCREF(maxsize_O);
976 obj->maxsize_O = maxsize_O;
977 Py_INCREF(func);
978 obj->func = func;
979 obj->wrapper = wrapper;
980 obj->misses = obj->hits = 0;
981 obj->typed = typed;
982 Py_INCREF(cache_info_type);
983 obj->cache_info_type = cache_info_type;
984
985 return (PyObject *)obj;
986}
987
988static lru_list_elem *
989lru_cache_unlink_list(lru_cache_object *self)
990{
991 lru_list_elem *root = &self->root;
992 lru_list_elem *link = root->next;
993 if (link == root)
994 return NULL;
995 root->prev->next = NULL;
996 root->next = root->prev = root;
997 return link;
998}
999
1000static void
1001lru_cache_clear_list(lru_list_elem *link)
1002{
1003 while (link != NULL) {
1004 lru_list_elem *next = link->next;
1005 Py_DECREF(link);
1006 link = next;
1007 }
1008}
1009
1010static void
1011lru_cache_dealloc(lru_cache_object *obj)
1012{
1013 lru_list_elem *list = lru_cache_unlink_list(obj);
1014 Py_XDECREF(obj->maxsize_O);
1015 Py_XDECREF(obj->func);
1016 Py_XDECREF(obj->cache);
1017 Py_XDECREF(obj->dict);
1018 Py_XDECREF(obj->cache_info_type);
1019 lru_cache_clear_list(list);
1020 Py_TYPE(obj)->tp_free(obj);
1021}
1022
1023static PyObject *
1024lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1025{
1026 return self->wrapper(self, args, kwds);
1027}
1028
1029static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001030lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1031{
1032 if (obj == Py_None || obj == NULL) {
1033 Py_INCREF(self);
1034 return self;
1035 }
1036 return PyMethod_New(self, obj);
1037}
1038
1039static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001040lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1041{
1042 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1043 self->hits, self->misses, self->maxsize_O,
1044 PyDict_Size(self->cache));
1045}
1046
1047static PyObject *
1048lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1049{
1050 lru_list_elem *list = lru_cache_unlink_list(self);
1051 self->hits = self->misses = 0;
1052 self->full = 0;
1053 PyDict_Clear(self->cache);
1054 lru_cache_clear_list(list);
1055 Py_RETURN_NONE;
1056}
1057
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001058static PyObject *
1059lru_cache_reduce(PyObject *self, PyObject *unused)
1060{
1061 return PyObject_GetAttrString(self, "__qualname__");
1062}
1063
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001064static PyObject *
1065lru_cache_copy(PyObject *self, PyObject *unused)
1066{
1067 Py_INCREF(self);
1068 return self;
1069}
1070
1071static PyObject *
1072lru_cache_deepcopy(PyObject *self, PyObject *unused)
1073{
1074 Py_INCREF(self);
1075 return self;
1076}
1077
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001078static int
1079lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1080{
1081 lru_list_elem *link = self->root.next;
1082 while (link != &self->root) {
1083 lru_list_elem *next = link->next;
1084 Py_VISIT(link);
1085 link = next;
1086 }
1087 Py_VISIT(self->maxsize_O);
1088 Py_VISIT(self->func);
1089 Py_VISIT(self->cache);
1090 Py_VISIT(self->cache_info_type);
1091 Py_VISIT(self->dict);
1092 return 0;
1093}
1094
1095static int
1096lru_cache_tp_clear(lru_cache_object *self)
1097{
1098 lru_list_elem *list = lru_cache_unlink_list(self);
1099 Py_CLEAR(self->maxsize_O);
1100 Py_CLEAR(self->func);
1101 Py_CLEAR(self->cache);
1102 Py_CLEAR(self->cache_info_type);
1103 Py_CLEAR(self->dict);
1104 lru_cache_clear_list(list);
1105 return 0;
1106}
1107
1108
1109PyDoc_STRVAR(lru_cache_doc,
1110"Create a cached callable that wraps another function.\n\
1111\n\
1112user_function: the function being cached\n\
1113\n\
1114maxsize: 0 for no caching\n\
1115 None for unlimited cache size\n\
1116 n for a bounded cache\n\
1117\n\
1118typed: False cache f(3) and f(3.0) as identical calls\n\
1119 True cache f(3) and f(3.0) as distinct calls\n\
1120\n\
1121cache_info_type: namedtuple class with the fields:\n\
1122 hits misses currsize maxsize\n"
1123);
1124
1125static PyMethodDef lru_cache_methods[] = {
1126 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1127 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001128 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001129 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1130 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001131 {NULL}
1132};
1133
1134static PyGetSetDef lru_cache_getsetlist[] = {
1135 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1136 {NULL}
1137};
1138
1139static PyTypeObject lru_cache_type = {
1140 PyVarObject_HEAD_INIT(NULL, 0)
1141 "functools._lru_cache_wrapper", /* tp_name */
1142 sizeof(lru_cache_object), /* tp_basicsize */
1143 0, /* tp_itemsize */
1144 /* methods */
1145 (destructor)lru_cache_dealloc, /* tp_dealloc */
1146 0, /* tp_print */
1147 0, /* tp_getattr */
1148 0, /* tp_setattr */
1149 0, /* tp_reserved */
1150 0, /* tp_repr */
1151 0, /* tp_as_number */
1152 0, /* tp_as_sequence */
1153 0, /* tp_as_mapping */
1154 0, /* tp_hash */
1155 (ternaryfunc)lru_cache_call, /* tp_call */
1156 0, /* tp_str */
1157 0, /* tp_getattro */
1158 0, /* tp_setattro */
1159 0, /* tp_as_buffer */
1160 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1161 /* tp_flags */
1162 lru_cache_doc, /* tp_doc */
1163 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1164 (inquiry)lru_cache_tp_clear, /* tp_clear */
1165 0, /* tp_richcompare */
1166 0, /* tp_weaklistoffset */
1167 0, /* tp_iter */
1168 0, /* tp_iternext */
1169 lru_cache_methods, /* tp_methods */
1170 0, /* tp_members */
1171 lru_cache_getsetlist, /* tp_getset */
1172 0, /* tp_base */
1173 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001174 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001175 0, /* tp_descr_set */
1176 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1177 0, /* tp_init */
1178 0, /* tp_alloc */
1179 lru_cache_new, /* tp_new */
1180};
1181
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001182/* module level code ********************************************************/
1183
1184PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001185"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001186
1187static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001188 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001189 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1190 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001191 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001192};
1193
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001194static void
1195module_free(void *m)
1196{
1197 Py_CLEAR(kwd_mark);
1198}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001199
1200static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001201 PyModuleDef_HEAD_INIT,
1202 "_functools",
1203 module_doc,
1204 -1,
1205 module_methods,
1206 NULL,
1207 NULL,
1208 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001209 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001210};
1211
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001212PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001213PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001214{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001215 int i;
1216 PyObject *m;
1217 char *name;
1218 PyTypeObject *typelist[] = {
1219 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001220 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001221 NULL
1222 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001223
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001224 m = PyModule_Create(&_functoolsmodule);
1225 if (m == NULL)
1226 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001227
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001228 kwd_mark = PyObject_CallObject((PyObject *)&PyBaseObject_Type, NULL);
1229 if (!kwd_mark) {
1230 Py_DECREF(m);
1231 return NULL;
1232 }
1233
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001234 for (i=0 ; typelist[i] != NULL ; i++) {
1235 if (PyType_Ready(typelist[i]) < 0) {
1236 Py_DECREF(m);
1237 return NULL;
1238 }
1239 name = strchr(typelist[i]->tp_name, '.');
1240 assert (name != NULL);
1241 Py_INCREF(typelist[i]);
1242 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1243 }
1244 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001245}