blob: 1bcf16a7e00f53998e6c53d393e40dd015547c45 [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 }
Serhiy Storchakae48fd932017-02-21 18:18:27 +020091 else if (Py_REFCNT(kw) == 1) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020092 Py_INCREF(kw);
93 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000094 }
Serhiy Storchakae48fd932017-02-21 18:18:27 +020095 else {
96 pto->kw = PyDict_Copy(kw);
97 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050098 }
99 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200100 pto->kw = PyDict_Copy(pkw);
101 if (kw != NULL && pto->kw != NULL) {
102 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -0400103 Py_DECREF(pto);
104 return NULL;
105 }
106 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000107 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200108 if (pto->kw == NULL) {
109 Py_DECREF(pto);
110 return NULL;
111 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000112
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 return (PyObject *)pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000114}
115
116static void
117partial_dealloc(partialobject *pto)
118{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000119 PyObject_GC_UnTrack(pto);
120 if (pto->weakreflist != NULL)
121 PyObject_ClearWeakRefs((PyObject *) pto);
122 Py_XDECREF(pto->fn);
123 Py_XDECREF(pto->args);
124 Py_XDECREF(pto->kw);
125 Py_XDECREF(pto->dict);
126 Py_TYPE(pto)->tp_free(pto);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000127}
128
129static PyObject *
130partial_call(partialobject *pto, PyObject *args, PyObject *kw)
131{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 PyObject *ret;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200133 PyObject *argappl, *kwappl;
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200134 PyObject **stack;
135 Py_ssize_t nargs;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000136
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 assert (PyCallable_Check(pto->fn));
138 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200139 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000140
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000141 if (PyTuple_GET_SIZE(pto->args) == 0) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200142 stack = &PyTuple_GET_ITEM(args, 0);
143 nargs = PyTuple_GET_SIZE(args);
144 argappl = NULL;
145 }
146 else if (PyTuple_GET_SIZE(args) == 0) {
147 stack = &PyTuple_GET_ITEM(pto->args, 0);
148 nargs = PyTuple_GET_SIZE(pto->args);
149 argappl = NULL;
150 }
151 else {
152 stack = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000153 argappl = PySequence_Concat(pto->args, args);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200154 if (argappl == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000155 return NULL;
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200156 }
157
Serhiy Storchaka38741282016-02-02 18:45:17 +0200158 assert(PyTuple_Check(argappl));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000160
Serhiy Storchaka38741282016-02-02 18:45:17 +0200161 if (PyDict_Size(pto->kw) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 kwappl = kw;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200163 Py_XINCREF(kwappl);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200164 }
165 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 kwappl = PyDict_Copy(pto->kw);
167 if (kwappl == NULL) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200168 Py_XDECREF(argappl);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000169 return NULL;
170 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 if (kw != NULL) {
173 if (PyDict_Merge(kwappl, kw, 1) != 0) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200174 Py_XDECREF(argappl);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 Py_DECREF(kwappl);
176 return NULL;
177 }
178 }
179 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000180
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200181 if (stack) {
182 ret = _PyObject_FastCallDict(pto->fn, stack, nargs, kwappl);
183 }
184 else {
185 ret = PyObject_Call(pto->fn, argappl, kwappl);
186 Py_DECREF(argappl);
187 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000188 Py_XDECREF(kwappl);
189 return ret;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000190}
191
192static int
193partial_traverse(partialobject *pto, visitproc visit, void *arg)
194{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 Py_VISIT(pto->fn);
196 Py_VISIT(pto->args);
197 Py_VISIT(pto->kw);
198 Py_VISIT(pto->dict);
199 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000200}
201
202PyDoc_STRVAR(partial_doc,
203"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000205
206#define OFF(x) offsetof(partialobject, x)
207static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 {"func", T_OBJECT, OFF(fn), READONLY,
209 "function object to use in future partial calls"},
210 {"args", T_OBJECT, OFF(args), READONLY,
211 "tuple of arguments to future partial calls"},
212 {"keywords", T_OBJECT, OFF(kw), READONLY,
213 "dictionary of keyword arguments to future partial calls"},
214 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000215};
216
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000217static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500218 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000219 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000220};
221
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000222static PyObject *
223partial_repr(partialobject *pto)
224{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300225 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000226 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000227 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200228 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300229 int status;
230
231 status = Py_ReprEnter((PyObject *)pto);
232 if (status != 0) {
233 if (status < 0)
234 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000235 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300236 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000237
238 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300239 if (arglist == NULL)
240 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000241 /* Pack positional arguments */
242 assert (PyTuple_Check(pto->args));
243 n = PyTuple_GET_SIZE(pto->args);
244 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300245 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
246 PyTuple_GET_ITEM(pto->args, i)));
247 if (arglist == NULL)
248 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000249 }
250 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200251 assert (PyDict_Check(pto->kw));
252 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Michael Seifert53b26672017-03-15 08:42:02 +0100253 /* Prevent key.__str__ from deleting the value. */
254 Py_INCREF(value);
255 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300256 key, value));
Michael Seifert53b26672017-03-15 08:42:02 +0100257 Py_DECREF(value);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300258 if (arglist == NULL)
259 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000260 }
261 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
262 pto->fn, arglist);
263 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300264
265 done:
266 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000267 return result;
268}
269
Jack Diederiche0cbd692009-04-01 04:27:09 +0000270/* Pickle strategy:
271 __reduce__ by itself doesn't support getting kwargs in the unpickle
272 operation so we define a __setstate__ that replaces all the information
273 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200274 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000275 */
276
Antoine Pitrou69f71142009-05-24 21:25:49 +0000277static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000278partial_reduce(partialobject *pto, PyObject *unused)
279{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000280 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
281 pto->args, pto->kw,
282 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000283}
284
Antoine Pitrou69f71142009-05-24 21:25:49 +0000285static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200286partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000287{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000288 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200289
290 if (!PyTuple_Check(state) ||
291 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
292 !PyCallable_Check(fn) ||
293 !PyTuple_Check(fnargs) ||
294 (kw != Py_None && !PyDict_Check(kw)))
295 {
296 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000297 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200299
300 if(!PyTuple_CheckExact(fnargs))
301 fnargs = PySequence_Tuple(fnargs);
302 else
303 Py_INCREF(fnargs);
304 if (fnargs == NULL)
305 return NULL;
306
307 if (kw == Py_None)
308 kw = PyDict_New();
309 else if(!PyDict_CheckExact(kw))
310 kw = PyDict_Copy(kw);
311 else
312 Py_INCREF(kw);
313 if (kw == NULL) {
314 Py_DECREF(fnargs);
315 return NULL;
316 }
317
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 Py_INCREF(fn);
Serhiy Storchaka38741282016-02-02 18:45:17 +0200319 if (dict == Py_None)
320 dict = NULL;
321 else
322 Py_INCREF(dict);
323
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300324 Py_SETREF(pto->fn, fn);
325 Py_SETREF(pto->args, fnargs);
326 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300327 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000328 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000329}
330
331static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200333 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000334 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000335};
336
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000337static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000338 PyVarObject_HEAD_INIT(NULL, 0)
339 "functools.partial", /* tp_name */
340 sizeof(partialobject), /* tp_basicsize */
341 0, /* tp_itemsize */
342 /* methods */
343 (destructor)partial_dealloc, /* tp_dealloc */
344 0, /* tp_print */
345 0, /* tp_getattr */
346 0, /* tp_setattr */
347 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000348 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 0, /* tp_as_number */
350 0, /* tp_as_sequence */
351 0, /* tp_as_mapping */
352 0, /* tp_hash */
353 (ternaryfunc)partial_call, /* tp_call */
354 0, /* tp_str */
355 PyObject_GenericGetAttr, /* tp_getattro */
356 PyObject_GenericSetAttr, /* tp_setattro */
357 0, /* tp_as_buffer */
358 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
359 Py_TPFLAGS_BASETYPE, /* tp_flags */
360 partial_doc, /* tp_doc */
361 (traverseproc)partial_traverse, /* tp_traverse */
362 0, /* tp_clear */
363 0, /* tp_richcompare */
364 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
365 0, /* tp_iter */
366 0, /* tp_iternext */
367 partial_methods, /* tp_methods */
368 partial_memberlist, /* tp_members */
369 partial_getsetlist, /* tp_getset */
370 0, /* tp_base */
371 0, /* tp_dict */
372 0, /* tp_descr_get */
373 0, /* tp_descr_set */
374 offsetof(partialobject, dict), /* tp_dictoffset */
375 0, /* tp_init */
376 0, /* tp_alloc */
377 partial_new, /* tp_new */
378 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000379};
380
381
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700382/* cmp_to_key ***************************************************************/
383
384typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200385 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700386 PyObject *cmp;
387 PyObject *object;
388} keyobject;
389
390static void
391keyobject_dealloc(keyobject *ko)
392{
393 Py_DECREF(ko->cmp);
394 Py_XDECREF(ko->object);
395 PyObject_FREE(ko);
396}
397
398static int
399keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
400{
401 Py_VISIT(ko->cmp);
402 if (ko->object)
403 Py_VISIT(ko->object);
404 return 0;
405}
406
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500407static int
408keyobject_clear(keyobject *ko)
409{
410 Py_CLEAR(ko->cmp);
411 if (ko->object)
412 Py_CLEAR(ko->object);
413 return 0;
414}
415
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700416static PyMemberDef keyobject_members[] = {
417 {"obj", T_OBJECT,
418 offsetof(keyobject, object), 0,
419 PyDoc_STR("Value wrapped by a key function.")},
420 {NULL}
421};
422
423static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700424keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700425
426static PyObject *
427keyobject_richcompare(PyObject *ko, PyObject *other, int op);
428
429static PyTypeObject keyobject_type = {
430 PyVarObject_HEAD_INIT(&PyType_Type, 0)
431 "functools.KeyWrapper", /* tp_name */
432 sizeof(keyobject), /* tp_basicsize */
433 0, /* tp_itemsize */
434 /* methods */
435 (destructor)keyobject_dealloc, /* tp_dealloc */
436 0, /* tp_print */
437 0, /* tp_getattr */
438 0, /* tp_setattr */
439 0, /* tp_reserved */
440 0, /* tp_repr */
441 0, /* tp_as_number */
442 0, /* tp_as_sequence */
443 0, /* tp_as_mapping */
444 0, /* tp_hash */
445 (ternaryfunc)keyobject_call, /* tp_call */
446 0, /* tp_str */
447 PyObject_GenericGetAttr, /* tp_getattro */
448 0, /* tp_setattro */
449 0, /* tp_as_buffer */
450 Py_TPFLAGS_DEFAULT, /* tp_flags */
451 0, /* tp_doc */
452 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500453 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700454 keyobject_richcompare, /* tp_richcompare */
455 0, /* tp_weaklistoffset */
456 0, /* tp_iter */
457 0, /* tp_iternext */
458 0, /* tp_methods */
459 keyobject_members, /* tp_members */
460 0, /* tp_getset */
461};
462
463static PyObject *
464keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
465{
466 PyObject *object;
467 keyobject *result;
468 static char *kwargs[] = {"obj", NULL};
469
470 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
471 return NULL;
472 result = PyObject_New(keyobject, &keyobject_type);
473 if (!result)
474 return NULL;
475 Py_INCREF(ko->cmp);
476 result->cmp = ko->cmp;
477 Py_INCREF(object);
478 result->object = object;
479 return (PyObject *)result;
480}
481
482static PyObject *
483keyobject_richcompare(PyObject *ko, PyObject *other, int op)
484{
485 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700486 PyObject *x;
487 PyObject *y;
488 PyObject *compare;
489 PyObject *answer;
490 static PyObject *zero;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200491 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700492
493 if (zero == NULL) {
494 zero = PyLong_FromLong(0);
495 if (!zero)
496 return NULL;
497 }
498
499 if (Py_TYPE(other) != &keyobject_type){
500 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
501 return NULL;
502 }
503 compare = ((keyobject *) ko)->cmp;
504 assert(compare != NULL);
505 x = ((keyobject *) ko)->object;
506 y = ((keyobject *) other)->object;
507 if (!x || !y){
508 PyErr_Format(PyExc_AttributeError, "object");
509 return NULL;
510 }
511
512 /* Call the user's comparison function and translate the 3-way
513 * result into true or false (or error).
514 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200515 stack[0] = x;
516 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200517 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200518 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700519 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200520 }
521
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700522 answer = PyObject_RichCompare(res, zero, op);
523 Py_DECREF(res);
524 return answer;
525}
526
527static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200528functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
529{
530 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700531 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200532 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700533
534 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
535 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200536 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700537 if (!object)
538 return NULL;
539 Py_INCREF(cmp);
540 object->cmp = cmp;
541 object->object = NULL;
542 return (PyObject *)object;
543}
544
545PyDoc_STRVAR(functools_cmp_to_key_doc,
546"Convert a cmp= function into a key= function.");
547
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000548/* reduce (used to be a builtin) ********************************************/
549
550static PyObject *
551functools_reduce(PyObject *self, PyObject *args)
552{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000553 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000554
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
556 return NULL;
557 if (result != NULL)
558 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000559
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000560 it = PyObject_GetIter(seq);
561 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000562 if (PyErr_ExceptionMatches(PyExc_TypeError))
563 PyErr_SetString(PyExc_TypeError,
564 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000565 Py_XDECREF(result);
566 return NULL;
567 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000568
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000569 if ((args = PyTuple_New(2)) == NULL)
570 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000571
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000572 for (;;) {
573 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000574
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 if (args->ob_refcnt > 1) {
576 Py_DECREF(args);
577 if ((args = PyTuple_New(2)) == NULL)
578 goto Fail;
579 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000580
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000581 op2 = PyIter_Next(it);
582 if (op2 == NULL) {
583 if (PyErr_Occurred())
584 goto Fail;
585 break;
586 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000587
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 if (result == NULL)
589 result = op2;
590 else {
591 PyTuple_SetItem(args, 0, result);
592 PyTuple_SetItem(args, 1, op2);
593 if ((result = PyEval_CallObject(func, args)) == NULL)
594 goto Fail;
595 }
596 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000597
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000598 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000599
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000600 if (result == NULL)
601 PyErr_SetString(PyExc_TypeError,
602 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000603
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000604 Py_DECREF(it);
605 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000606
607Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000608 Py_XDECREF(args);
609 Py_XDECREF(result);
610 Py_DECREF(it);
611 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000612}
613
614PyDoc_STRVAR(functools_reduce_doc,
615"reduce(function, sequence[, initial]) -> value\n\
616\n\
617Apply a function of two arguments cumulatively to the items of a sequence,\n\
618from left to right, so as to reduce the sequence to a single value.\n\
619For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
620((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
621of the sequence in the calculation, and serves as a default when the\n\
622sequence is empty.");
623
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300624/* lru_cache object **********************************************************/
625
626/* this object is used delimit args and keywords in the cache keys */
627static PyObject *kwd_mark = NULL;
628
629struct lru_list_elem;
630struct lru_cache_object;
631
632typedef struct lru_list_elem {
633 PyObject_HEAD
634 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300635 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300636 PyObject *key, *result;
637} lru_list_elem;
638
639static void
640lru_list_elem_dealloc(lru_list_elem *link)
641{
642 _PyObject_GC_UNTRACK(link);
643 Py_XDECREF(link->key);
644 Py_XDECREF(link->result);
645 PyObject_GC_Del(link);
646}
647
648static int
649lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
650{
651 Py_VISIT(link->key);
652 Py_VISIT(link->result);
653 return 0;
654}
655
656static int
657lru_list_elem_clear(lru_list_elem *link)
658{
659 Py_CLEAR(link->key);
660 Py_CLEAR(link->result);
661 return 0;
662}
663
664static PyTypeObject lru_list_elem_type = {
665 PyVarObject_HEAD_INIT(&PyType_Type, 0)
666 "functools._lru_list_elem", /* tp_name */
667 sizeof(lru_list_elem), /* tp_basicsize */
668 0, /* tp_itemsize */
669 /* methods */
670 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
671 0, /* tp_print */
672 0, /* tp_getattr */
673 0, /* tp_setattr */
674 0, /* tp_reserved */
675 0, /* tp_repr */
676 0, /* tp_as_number */
677 0, /* tp_as_sequence */
678 0, /* tp_as_mapping */
679 0, /* tp_hash */
680 0, /* tp_call */
681 0, /* tp_str */
682 0, /* tp_getattro */
683 0, /* tp_setattro */
684 0, /* tp_as_buffer */
685 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
686 0, /* tp_doc */
687 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
688 (inquiry)lru_list_elem_clear, /* tp_clear */
689};
690
691
692typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
693
694typedef struct lru_cache_object {
695 lru_list_elem root; /* includes PyObject_HEAD */
696 Py_ssize_t maxsize;
697 PyObject *maxsize_O;
698 PyObject *func;
699 lru_cache_ternaryfunc wrapper;
700 PyObject *cache;
701 PyObject *cache_info_type;
702 Py_ssize_t misses, hits;
703 int typed;
704 PyObject *dict;
705 int full;
706} lru_cache_object;
707
708static PyTypeObject lru_cache_type;
709
710static PyObject *
711lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
712{
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800713 PyObject *key, *keyword, *value;
714 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300715
716 /* short path, key will match args anyway, which is a tuple */
717 if (!typed && !kwds) {
718 Py_INCREF(args);
719 return args;
720 }
721
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800722 kwds_size = kwds ? PyDict_Size(kwds) : 0;
723 assert(kwds_size >= 0);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300724
725 key_size = PyTuple_GET_SIZE(args);
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800726 if (kwds_size)
727 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300728 if (typed)
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800729 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300730
731 key = PyTuple_New(key_size);
732 if (key == NULL)
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800733 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300734
735 key_pos = 0;
736 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
737 PyObject *item = PyTuple_GET_ITEM(args, pos);
738 Py_INCREF(item);
739 PyTuple_SET_ITEM(key, key_pos++, item);
740 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800741 if (kwds_size) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300742 Py_INCREF(kwd_mark);
743 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800744 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
745 Py_INCREF(keyword);
746 PyTuple_SET_ITEM(key, key_pos++, keyword);
747 Py_INCREF(value);
748 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300749 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800750 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300751 }
752 if (typed) {
753 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
754 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
755 Py_INCREF(item);
756 PyTuple_SET_ITEM(key, key_pos++, item);
757 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800758 if (kwds_size) {
759 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
760 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300761 Py_INCREF(item);
762 PyTuple_SET_ITEM(key, key_pos++, item);
763 }
764 }
765 }
766 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300767 return key;
768}
769
770static PyObject *
771uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
772{
773 PyObject *result = PyObject_Call(self->func, args, kwds);
774 if (!result)
775 return NULL;
776 self->misses++;
777 return result;
778}
779
780static PyObject *
781infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
782{
783 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300784 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300785 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
786 if (!key)
787 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300788 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500789 if (hash == -1) {
790 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300791 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500792 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300793 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300794 if (result) {
795 Py_INCREF(result);
796 self->hits++;
797 Py_DECREF(key);
798 return result;
799 }
800 if (PyErr_Occurred()) {
801 Py_DECREF(key);
802 return NULL;
803 }
804 result = PyObject_Call(self->func, args, kwds);
805 if (!result) {
806 Py_DECREF(key);
807 return NULL;
808 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300809 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300810 Py_DECREF(result);
811 Py_DECREF(key);
812 return NULL;
813 }
814 Py_DECREF(key);
815 self->misses++;
816 return result;
817}
818
819static void
820lru_cache_extricate_link(lru_list_elem *link)
821{
822 link->prev->next = link->next;
823 link->next->prev = link->prev;
824}
825
826static void
827lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
828{
829 lru_list_elem *root = &self->root;
830 lru_list_elem *last = root->prev;
831 last->next = root->prev = link;
832 link->prev = last;
833 link->next = root;
834}
835
836static PyObject *
837bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
838{
839 lru_list_elem *link;
840 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300841 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300842
843 key = lru_cache_make_key(args, kwds, self->typed);
844 if (!key)
845 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300846 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500847 if (hash == -1) {
848 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300849 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500850 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300851 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300852 if (link) {
853 lru_cache_extricate_link(link);
854 lru_cache_append_link(self, link);
855 self->hits++;
856 result = link->result;
857 Py_INCREF(result);
858 Py_DECREF(key);
859 return result;
860 }
861 if (PyErr_Occurred()) {
862 Py_DECREF(key);
863 return NULL;
864 }
865 result = PyObject_Call(self->func, args, kwds);
866 if (!result) {
867 Py_DECREF(key);
868 return NULL;
869 }
870 if (self->full && self->root.next != &self->root) {
871 /* Use the oldest item to store the new key and result. */
Serhiy Storchaka67796522017-01-12 18:34:33 +0200872 PyObject *oldkey, *oldresult, *popresult;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300873 /* Extricate the oldest item. */
874 link = self->root.next;
875 lru_cache_extricate_link(link);
876 /* Remove it from the cache.
877 The cache dict holds one reference to the link,
878 and the linked list holds yet one reference to it. */
Serhiy Storchaka42e1ea92017-01-12 19:12:21 +0200879 popresult = _PyDict_Pop_KnownHash(self->cache,
Serhiy Storchaka67796522017-01-12 18:34:33 +0200880 link->key, link->hash,
881 Py_None);
882 if (popresult == Py_None) {
883 /* Getting here means that this same key was added to the
884 cache while the lock was released. Since the link
885 update is already done, we need only return the
886 computed result and update the count of misses. */
887 Py_DECREF(popresult);
888 Py_DECREF(link);
889 Py_DECREF(key);
890 }
891 else if (popresult == NULL) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300892 lru_cache_append_link(self, link);
893 Py_DECREF(key);
894 Py_DECREF(result);
895 return NULL;
896 }
Serhiy Storchaka67796522017-01-12 18:34:33 +0200897 else {
898 Py_DECREF(popresult);
899 /* Keep a reference to the old key and old result to
900 prevent their ref counts from going to zero during the
901 update. That will prevent potentially arbitrary object
902 clean-up code (i.e. __del__) from running while we're
903 still adjusting the links. */
904 oldkey = link->key;
905 oldresult = link->result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300906
Serhiy Storchaka67796522017-01-12 18:34:33 +0200907 link->hash = hash;
908 link->key = key;
909 link->result = result;
910 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
911 hash) < 0) {
912 Py_DECREF(link);
913 Py_DECREF(oldkey);
914 Py_DECREF(oldresult);
915 return NULL;
916 }
917 lru_cache_append_link(self, link);
918 Py_INCREF(result); /* for return */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300919 Py_DECREF(oldkey);
920 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300921 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300922 } else {
923 /* Put result in a new link at the front of the queue. */
924 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
925 &lru_list_elem_type);
926 if (link == NULL) {
927 Py_DECREF(key);
928 Py_DECREF(result);
929 return NULL;
930 }
931
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300932 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300933 link->key = key;
934 link->result = result;
935 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300936 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
937 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300938 Py_DECREF(link);
939 return NULL;
940 }
941 lru_cache_append_link(self, link);
942 Py_INCREF(result); /* for return */
943 self->full = (PyDict_Size(self->cache) >= self->maxsize);
944 }
945 self->misses++;
946 return result;
947}
948
949static PyObject *
950lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
951{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300952 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300953 int typed;
954 lru_cache_object *obj;
955 Py_ssize_t maxsize;
956 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
957 static char *keywords[] = {"user_function", "maxsize", "typed",
958 "cache_info_type", NULL};
959
960 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
961 &func, &maxsize_O, &typed,
962 &cache_info_type)) {
963 return NULL;
964 }
965
966 if (!PyCallable_Check(func)) {
967 PyErr_SetString(PyExc_TypeError,
968 "the first argument must be callable");
969 return NULL;
970 }
971
972 /* select the caching function, and make/inc maxsize_O */
973 if (maxsize_O == Py_None) {
974 wrapper = infinite_lru_cache_wrapper;
975 /* use this only to initialize lru_cache_object attribute maxsize */
976 maxsize = -1;
977 } else if (PyIndex_Check(maxsize_O)) {
978 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
979 if (maxsize == -1 && PyErr_Occurred())
980 return NULL;
981 if (maxsize == 0)
982 wrapper = uncached_lru_cache_wrapper;
983 else
984 wrapper = bounded_lru_cache_wrapper;
985 } else {
986 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
987 return NULL;
988 }
989
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300990 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300991 return NULL;
992
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300993 obj = (lru_cache_object *)type->tp_alloc(type, 0);
994 if (obj == NULL) {
995 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300996 return NULL;
997 }
998
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300999 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001000 obj->root.prev = &obj->root;
1001 obj->root.next = &obj->root;
1002 obj->maxsize = maxsize;
1003 Py_INCREF(maxsize_O);
1004 obj->maxsize_O = maxsize_O;
1005 Py_INCREF(func);
1006 obj->func = func;
1007 obj->wrapper = wrapper;
1008 obj->misses = obj->hits = 0;
1009 obj->typed = typed;
1010 Py_INCREF(cache_info_type);
1011 obj->cache_info_type = cache_info_type;
1012
1013 return (PyObject *)obj;
1014}
1015
1016static lru_list_elem *
1017lru_cache_unlink_list(lru_cache_object *self)
1018{
1019 lru_list_elem *root = &self->root;
1020 lru_list_elem *link = root->next;
1021 if (link == root)
1022 return NULL;
1023 root->prev->next = NULL;
1024 root->next = root->prev = root;
1025 return link;
1026}
1027
1028static void
1029lru_cache_clear_list(lru_list_elem *link)
1030{
1031 while (link != NULL) {
1032 lru_list_elem *next = link->next;
1033 Py_DECREF(link);
1034 link = next;
1035 }
1036}
1037
1038static void
1039lru_cache_dealloc(lru_cache_object *obj)
1040{
1041 lru_list_elem *list = lru_cache_unlink_list(obj);
1042 Py_XDECREF(obj->maxsize_O);
1043 Py_XDECREF(obj->func);
1044 Py_XDECREF(obj->cache);
1045 Py_XDECREF(obj->dict);
1046 Py_XDECREF(obj->cache_info_type);
1047 lru_cache_clear_list(list);
1048 Py_TYPE(obj)->tp_free(obj);
1049}
1050
1051static PyObject *
1052lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1053{
1054 return self->wrapper(self, args, kwds);
1055}
1056
1057static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001058lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1059{
1060 if (obj == Py_None || obj == NULL) {
1061 Py_INCREF(self);
1062 return self;
1063 }
1064 return PyMethod_New(self, obj);
1065}
1066
1067static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001068lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1069{
1070 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1071 self->hits, self->misses, self->maxsize_O,
1072 PyDict_Size(self->cache));
1073}
1074
1075static PyObject *
1076lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1077{
1078 lru_list_elem *list = lru_cache_unlink_list(self);
1079 self->hits = self->misses = 0;
1080 self->full = 0;
1081 PyDict_Clear(self->cache);
1082 lru_cache_clear_list(list);
1083 Py_RETURN_NONE;
1084}
1085
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001086static PyObject *
1087lru_cache_reduce(PyObject *self, PyObject *unused)
1088{
1089 return PyObject_GetAttrString(self, "__qualname__");
1090}
1091
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001092static PyObject *
1093lru_cache_copy(PyObject *self, PyObject *unused)
1094{
1095 Py_INCREF(self);
1096 return self;
1097}
1098
1099static PyObject *
1100lru_cache_deepcopy(PyObject *self, PyObject *unused)
1101{
1102 Py_INCREF(self);
1103 return self;
1104}
1105
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001106static int
1107lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1108{
1109 lru_list_elem *link = self->root.next;
1110 while (link != &self->root) {
1111 lru_list_elem *next = link->next;
1112 Py_VISIT(link);
1113 link = next;
1114 }
1115 Py_VISIT(self->maxsize_O);
1116 Py_VISIT(self->func);
1117 Py_VISIT(self->cache);
1118 Py_VISIT(self->cache_info_type);
1119 Py_VISIT(self->dict);
1120 return 0;
1121}
1122
1123static int
1124lru_cache_tp_clear(lru_cache_object *self)
1125{
1126 lru_list_elem *list = lru_cache_unlink_list(self);
1127 Py_CLEAR(self->maxsize_O);
1128 Py_CLEAR(self->func);
1129 Py_CLEAR(self->cache);
1130 Py_CLEAR(self->cache_info_type);
1131 Py_CLEAR(self->dict);
1132 lru_cache_clear_list(list);
1133 return 0;
1134}
1135
1136
1137PyDoc_STRVAR(lru_cache_doc,
1138"Create a cached callable that wraps another function.\n\
1139\n\
1140user_function: the function being cached\n\
1141\n\
1142maxsize: 0 for no caching\n\
1143 None for unlimited cache size\n\
1144 n for a bounded cache\n\
1145\n\
1146typed: False cache f(3) and f(3.0) as identical calls\n\
1147 True cache f(3) and f(3.0) as distinct calls\n\
1148\n\
1149cache_info_type: namedtuple class with the fields:\n\
1150 hits misses currsize maxsize\n"
1151);
1152
1153static PyMethodDef lru_cache_methods[] = {
1154 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1155 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001156 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001157 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1158 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001159 {NULL}
1160};
1161
1162static PyGetSetDef lru_cache_getsetlist[] = {
1163 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1164 {NULL}
1165};
1166
1167static PyTypeObject lru_cache_type = {
1168 PyVarObject_HEAD_INIT(NULL, 0)
1169 "functools._lru_cache_wrapper", /* tp_name */
1170 sizeof(lru_cache_object), /* tp_basicsize */
1171 0, /* tp_itemsize */
1172 /* methods */
1173 (destructor)lru_cache_dealloc, /* tp_dealloc */
1174 0, /* tp_print */
1175 0, /* tp_getattr */
1176 0, /* tp_setattr */
1177 0, /* tp_reserved */
1178 0, /* tp_repr */
1179 0, /* tp_as_number */
1180 0, /* tp_as_sequence */
1181 0, /* tp_as_mapping */
1182 0, /* tp_hash */
1183 (ternaryfunc)lru_cache_call, /* tp_call */
1184 0, /* tp_str */
1185 0, /* tp_getattro */
1186 0, /* tp_setattro */
1187 0, /* tp_as_buffer */
1188 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1189 /* tp_flags */
1190 lru_cache_doc, /* tp_doc */
1191 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1192 (inquiry)lru_cache_tp_clear, /* tp_clear */
1193 0, /* tp_richcompare */
1194 0, /* tp_weaklistoffset */
1195 0, /* tp_iter */
1196 0, /* tp_iternext */
1197 lru_cache_methods, /* tp_methods */
1198 0, /* tp_members */
1199 lru_cache_getsetlist, /* tp_getset */
1200 0, /* tp_base */
1201 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001202 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001203 0, /* tp_descr_set */
1204 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1205 0, /* tp_init */
1206 0, /* tp_alloc */
1207 lru_cache_new, /* tp_new */
1208};
1209
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001210/* module level code ********************************************************/
1211
1212PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001213"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001214
1215static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001216 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001217 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1218 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001219 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001220};
1221
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001222static void
1223module_free(void *m)
1224{
1225 Py_CLEAR(kwd_mark);
1226}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001227
1228static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001229 PyModuleDef_HEAD_INIT,
1230 "_functools",
1231 module_doc,
1232 -1,
1233 module_methods,
1234 NULL,
1235 NULL,
1236 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001237 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001238};
1239
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001240PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001241PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001242{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001243 int i;
1244 PyObject *m;
1245 char *name;
1246 PyTypeObject *typelist[] = {
1247 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001248 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001249 NULL
1250 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001251
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001252 m = PyModule_Create(&_functoolsmodule);
1253 if (m == NULL)
1254 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001255
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001256 kwd_mark = PyObject_CallObject((PyObject *)&PyBaseObject_Type, NULL);
1257 if (!kwd_mark) {
1258 Py_DECREF(m);
1259 return NULL;
1260 }
1261
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001262 for (i=0 ; typelist[i] != NULL ; i++) {
1263 if (PyType_Ready(typelist[i]) < 0) {
1264 Py_DECREF(m);
1265 return NULL;
1266 }
1267 name = strchr(typelist[i]->tp_name, '.');
1268 assert (name != NULL);
1269 Py_INCREF(typelist[i]);
1270 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1271 }
1272 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001273}