blob: da1d2e16dba746ec63338d5a247a568a8893d3ed [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 */
Victor Stinner0f7b0b32017-03-14 21:37:20 +010021 int use_fastcall;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000022} partialobject;
23
24static PyTypeObject partial_type;
25
26static PyObject *
27partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
28{
Alexander Belopolskye49af342015-03-01 15:08:17 -050029 PyObject *func, *pargs, *nargs, *pkw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000030 partialobject *pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000031
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000032 if (PyTuple_GET_SIZE(args) < 1) {
33 PyErr_SetString(PyExc_TypeError,
34 "type 'partial' takes at least one argument");
35 return NULL;
36 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000037
Serhiy Storchaka38741282016-02-02 18:45:17 +020038 pargs = pkw = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000039 func = PyTuple_GET_ITEM(args, 0);
Alexander Belopolskye49af342015-03-01 15:08:17 -050040 if (Py_TYPE(func) == &partial_type && type == &partial_type) {
41 partialobject *part = (partialobject *)func;
42 if (part->dict == NULL) {
43 pargs = part->args;
44 pkw = part->kw;
45 func = part->fn;
Serhiy Storchaka38741282016-02-02 18:45:17 +020046 assert(PyTuple_Check(pargs));
47 assert(PyDict_Check(pkw));
Alexander Belopolskye49af342015-03-01 15:08:17 -050048 }
49 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000050 if (!PyCallable_Check(func)) {
51 PyErr_SetString(PyExc_TypeError,
52 "the first argument must be callable");
53 return NULL;
54 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000055
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000056 /* create partialobject structure */
57 pto = (partialobject *)type->tp_alloc(type, 0);
58 if (pto == NULL)
59 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000060
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000061 pto->fn = func;
62 Py_INCREF(func);
Alexander Belopolskye49af342015-03-01 15:08:17 -050063
64 nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
65 if (nargs == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000066 Py_DECREF(pto);
67 return NULL;
68 }
Serhiy Storchaka3c749fc2017-03-25 12:10:16 +020069 if (pargs == NULL) {
Alexander Belopolskye49af342015-03-01 15:08:17 -050070 pto->args = nargs;
Alexander Belopolskye49af342015-03-01 15:08:17 -050071 }
72 else {
73 pto->args = PySequence_Concat(pargs, nargs);
Serhiy Storchaka3c749fc2017-03-25 12:10:16 +020074 Py_DECREF(nargs);
Alexander Belopolskye49af342015-03-01 15:08:17 -050075 if (pto->args == NULL) {
Alexander Belopolskye49af342015-03-01 15:08:17 -050076 Py_DECREF(pto);
77 return NULL;
78 }
Serhiy Storchaka38741282016-02-02 18:45:17 +020079 assert(PyTuple_Check(pto->args));
Alexander Belopolskye49af342015-03-01 15:08:17 -050080 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050081
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +020082 if (pkw == NULL || PyDict_GET_SIZE(pkw) == 0) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020083 if (kw == NULL) {
84 pto->kw = PyDict_New();
Alexander Belopolskye49af342015-03-01 15:08:17 -050085 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +020086 else if (Py_REFCNT(kw) == 1) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020087 Py_INCREF(kw);
88 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000089 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +020090 else {
91 pto->kw = PyDict_Copy(kw);
92 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050093 }
94 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +020095 pto->kw = PyDict_Copy(pkw);
96 if (kw != NULL && pto->kw != NULL) {
97 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -040098 Py_DECREF(pto);
99 return NULL;
100 }
101 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000102 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200103 if (pto->kw == NULL) {
104 Py_DECREF(pto);
105 return NULL;
106 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000107
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100108 pto->use_fastcall = _PyObject_HasFastCall(func);
109
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 *
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100127partial_fastcall(partialobject *pto, PyObject **args, Py_ssize_t nargs,
128 PyObject *kwargs)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000129{
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100130 PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000131 PyObject *ret;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100132 PyObject **stack, **stack_buf = NULL;
133 Py_ssize_t nargs2, pto_nargs;
134
135 pto_nargs = PyTuple_GET_SIZE(pto->args);
136 nargs2 = pto_nargs + nargs;
137
138 if (pto_nargs == 0) {
139 stack = args;
140 }
141 else if (nargs == 0) {
142 stack = &PyTuple_GET_ITEM(pto->args, 0);
143 }
144 else {
145 if (nargs2 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
146 stack = small_stack;
147 }
148 else {
149 stack_buf = PyMem_Malloc(nargs2 * sizeof(PyObject *));
150 if (stack_buf == NULL) {
151 PyErr_NoMemory();
152 return NULL;
153 }
154 stack = stack_buf;
155 }
156
157 /* use borrowed references */
158 memcpy(stack,
159 &PyTuple_GET_ITEM(pto->args, 0),
160 pto_nargs * sizeof(PyObject*));
161 memcpy(&stack[pto_nargs],
162 args,
163 nargs * sizeof(PyObject*));
164 }
165
166 ret = _PyObject_FastCallDict(pto->fn, stack, nargs2, kwargs);
167 PyMem_Free(stack_buf);
168 return ret;
169}
170
171static PyObject *
172partial_call_impl(partialobject *pto, PyObject *args, PyObject *kwargs)
173{
174 PyObject *ret, *args2;
175
176 /* Note: tupleconcat() is optimized for empty tuples */
177 args2 = PySequence_Concat(pto->args, args);
178 if (args2 == NULL) {
179 return NULL;
180 }
181 assert(PyTuple_Check(args2));
182
183 ret = PyObject_Call(pto->fn, args2, kwargs);
184 Py_DECREF(args2);
185 return ret;
186}
187
188static PyObject *
189partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
190{
191 PyObject *kwargs2, *res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000192
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 assert (PyCallable_Check(pto->fn));
194 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200195 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000196
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200197 if (PyDict_GET_SIZE(pto->kw) == 0) {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100198 /* kwargs can be NULL */
199 kwargs2 = kwargs;
200 Py_XINCREF(kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200201 }
202 else {
Victor Stinner561ca802017-02-23 18:26:43 +0100203 /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
204 copied, because a function using "**kwargs" can modify the
205 dictionary. */
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100206 kwargs2 = PyDict_Copy(pto->kw);
207 if (kwargs2 == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 return NULL;
209 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200210
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100211 if (kwargs != NULL) {
212 if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
213 Py_DECREF(kwargs2);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214 return NULL;
215 }
216 }
217 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000218
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100219
220 if (pto->use_fastcall) {
221 res = partial_fastcall(pto,
222 &PyTuple_GET_ITEM(args, 0),
223 PyTuple_GET_SIZE(args),
224 kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200225 }
226 else {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100227 res = partial_call_impl(pto, args, kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200228 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100229 Py_XDECREF(kwargs2);
230 return res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000231}
232
233static int
234partial_traverse(partialobject *pto, visitproc visit, void *arg)
235{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 Py_VISIT(pto->fn);
237 Py_VISIT(pto->args);
238 Py_VISIT(pto->kw);
239 Py_VISIT(pto->dict);
240 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000241}
242
243PyDoc_STRVAR(partial_doc,
244"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000246
247#define OFF(x) offsetof(partialobject, x)
248static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000249 {"func", T_OBJECT, OFF(fn), READONLY,
250 "function object to use in future partial calls"},
251 {"args", T_OBJECT, OFF(args), READONLY,
252 "tuple of arguments to future partial calls"},
253 {"keywords", T_OBJECT, OFF(kw), READONLY,
254 "dictionary of keyword arguments to future partial calls"},
255 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000256};
257
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000258static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500259 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000260 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000261};
262
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000263static PyObject *
264partial_repr(partialobject *pto)
265{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300266 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000267 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000268 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200269 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300270 int status;
271
272 status = Py_ReprEnter((PyObject *)pto);
273 if (status != 0) {
274 if (status < 0)
275 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000276 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300277 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000278
279 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300280 if (arglist == NULL)
281 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000282 /* Pack positional arguments */
283 assert (PyTuple_Check(pto->args));
284 n = PyTuple_GET_SIZE(pto->args);
285 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300286 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
287 PyTuple_GET_ITEM(pto->args, i)));
288 if (arglist == NULL)
289 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000290 }
291 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200292 assert (PyDict_Check(pto->kw));
293 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Michael Seifert6c3d5272017-03-15 06:26:33 +0100294 /* Prevent key.__str__ from deleting the value. */
295 Py_INCREF(value);
296 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300297 key, value));
Michael Seifert6c3d5272017-03-15 06:26:33 +0100298 Py_DECREF(value);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300299 if (arglist == NULL)
300 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000301 }
302 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
303 pto->fn, arglist);
304 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300305
306 done:
307 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000308 return result;
309}
310
Jack Diederiche0cbd692009-04-01 04:27:09 +0000311/* Pickle strategy:
312 __reduce__ by itself doesn't support getting kwargs in the unpickle
313 operation so we define a __setstate__ that replaces all the information
314 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200315 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000316 */
317
Antoine Pitrou69f71142009-05-24 21:25:49 +0000318static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000319partial_reduce(partialobject *pto, PyObject *unused)
320{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000321 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
322 pto->args, pto->kw,
323 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000324}
325
Antoine Pitrou69f71142009-05-24 21:25:49 +0000326static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200327partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000328{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200330
331 if (!PyTuple_Check(state) ||
332 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
333 !PyCallable_Check(fn) ||
334 !PyTuple_Check(fnargs) ||
335 (kw != Py_None && !PyDict_Check(kw)))
336 {
337 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000338 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200340
341 if(!PyTuple_CheckExact(fnargs))
342 fnargs = PySequence_Tuple(fnargs);
343 else
344 Py_INCREF(fnargs);
345 if (fnargs == NULL)
346 return NULL;
347
348 if (kw == Py_None)
349 kw = PyDict_New();
350 else if(!PyDict_CheckExact(kw))
351 kw = PyDict_Copy(kw);
352 else
353 Py_INCREF(kw);
354 if (kw == NULL) {
355 Py_DECREF(fnargs);
356 return NULL;
357 }
358
Serhiy Storchaka38741282016-02-02 18:45:17 +0200359 if (dict == Py_None)
360 dict = NULL;
361 else
362 Py_INCREF(dict);
363
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100364 Py_INCREF(fn);
365 pto->use_fastcall = _PyObject_HasFastCall(fn);
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300366 Py_SETREF(pto->fn, fn);
367 Py_SETREF(pto->args, fnargs);
368 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300369 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000370 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000371}
372
373static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200375 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000376 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000377};
378
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000379static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000380 PyVarObject_HEAD_INIT(NULL, 0)
381 "functools.partial", /* tp_name */
382 sizeof(partialobject), /* tp_basicsize */
383 0, /* tp_itemsize */
384 /* methods */
385 (destructor)partial_dealloc, /* tp_dealloc */
386 0, /* tp_print */
387 0, /* tp_getattr */
388 0, /* tp_setattr */
389 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000390 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000391 0, /* tp_as_number */
392 0, /* tp_as_sequence */
393 0, /* tp_as_mapping */
394 0, /* tp_hash */
395 (ternaryfunc)partial_call, /* tp_call */
396 0, /* tp_str */
397 PyObject_GenericGetAttr, /* tp_getattro */
398 PyObject_GenericSetAttr, /* tp_setattro */
399 0, /* tp_as_buffer */
400 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
401 Py_TPFLAGS_BASETYPE, /* tp_flags */
402 partial_doc, /* tp_doc */
403 (traverseproc)partial_traverse, /* tp_traverse */
404 0, /* tp_clear */
405 0, /* tp_richcompare */
406 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
407 0, /* tp_iter */
408 0, /* tp_iternext */
409 partial_methods, /* tp_methods */
410 partial_memberlist, /* tp_members */
411 partial_getsetlist, /* tp_getset */
412 0, /* tp_base */
413 0, /* tp_dict */
414 0, /* tp_descr_get */
415 0, /* tp_descr_set */
416 offsetof(partialobject, dict), /* tp_dictoffset */
417 0, /* tp_init */
418 0, /* tp_alloc */
419 partial_new, /* tp_new */
420 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000421};
422
423
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700424/* cmp_to_key ***************************************************************/
425
426typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200427 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700428 PyObject *cmp;
429 PyObject *object;
430} keyobject;
431
432static void
433keyobject_dealloc(keyobject *ko)
434{
435 Py_DECREF(ko->cmp);
436 Py_XDECREF(ko->object);
437 PyObject_FREE(ko);
438}
439
440static int
441keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
442{
443 Py_VISIT(ko->cmp);
444 if (ko->object)
445 Py_VISIT(ko->object);
446 return 0;
447}
448
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500449static int
450keyobject_clear(keyobject *ko)
451{
452 Py_CLEAR(ko->cmp);
453 if (ko->object)
454 Py_CLEAR(ko->object);
455 return 0;
456}
457
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700458static PyMemberDef keyobject_members[] = {
459 {"obj", T_OBJECT,
460 offsetof(keyobject, object), 0,
461 PyDoc_STR("Value wrapped by a key function.")},
462 {NULL}
463};
464
465static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700466keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700467
468static PyObject *
469keyobject_richcompare(PyObject *ko, PyObject *other, int op);
470
471static PyTypeObject keyobject_type = {
472 PyVarObject_HEAD_INIT(&PyType_Type, 0)
473 "functools.KeyWrapper", /* tp_name */
474 sizeof(keyobject), /* tp_basicsize */
475 0, /* tp_itemsize */
476 /* methods */
477 (destructor)keyobject_dealloc, /* tp_dealloc */
478 0, /* tp_print */
479 0, /* tp_getattr */
480 0, /* tp_setattr */
481 0, /* tp_reserved */
482 0, /* tp_repr */
483 0, /* tp_as_number */
484 0, /* tp_as_sequence */
485 0, /* tp_as_mapping */
486 0, /* tp_hash */
487 (ternaryfunc)keyobject_call, /* tp_call */
488 0, /* tp_str */
489 PyObject_GenericGetAttr, /* tp_getattro */
490 0, /* tp_setattro */
491 0, /* tp_as_buffer */
492 Py_TPFLAGS_DEFAULT, /* tp_flags */
493 0, /* tp_doc */
494 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500495 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700496 keyobject_richcompare, /* tp_richcompare */
497 0, /* tp_weaklistoffset */
498 0, /* tp_iter */
499 0, /* tp_iternext */
500 0, /* tp_methods */
501 keyobject_members, /* tp_members */
502 0, /* tp_getset */
503};
504
505static PyObject *
506keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
507{
508 PyObject *object;
509 keyobject *result;
510 static char *kwargs[] = {"obj", NULL};
511
512 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
513 return NULL;
514 result = PyObject_New(keyobject, &keyobject_type);
515 if (!result)
516 return NULL;
517 Py_INCREF(ko->cmp);
518 result->cmp = ko->cmp;
519 Py_INCREF(object);
520 result->object = object;
521 return (PyObject *)result;
522}
523
524static PyObject *
525keyobject_richcompare(PyObject *ko, PyObject *other, int op)
526{
527 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700528 PyObject *x;
529 PyObject *y;
530 PyObject *compare;
531 PyObject *answer;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200532 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700533
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700534 if (Py_TYPE(other) != &keyobject_type){
535 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
536 return NULL;
537 }
538 compare = ((keyobject *) ko)->cmp;
539 assert(compare != NULL);
540 x = ((keyobject *) ko)->object;
541 y = ((keyobject *) other)->object;
542 if (!x || !y){
543 PyErr_Format(PyExc_AttributeError, "object");
544 return NULL;
545 }
546
547 /* Call the user's comparison function and translate the 3-way
548 * result into true or false (or error).
549 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200550 stack[0] = x;
551 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200552 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200553 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700554 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200555 }
556
Serhiy Storchakaba85d692017-03-30 09:09:41 +0300557 answer = PyObject_RichCompare(res, _PyLong_Zero, op);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700558 Py_DECREF(res);
559 return answer;
560}
561
562static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200563functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
564{
565 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700566 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200567 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700568
569 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
570 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200571 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700572 if (!object)
573 return NULL;
574 Py_INCREF(cmp);
575 object->cmp = cmp;
576 object->object = NULL;
577 return (PyObject *)object;
578}
579
580PyDoc_STRVAR(functools_cmp_to_key_doc,
581"Convert a cmp= function into a key= function.");
582
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000583/* reduce (used to be a builtin) ********************************************/
584
585static PyObject *
586functools_reduce(PyObject *self, PyObject *args)
587{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000589
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000590 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
591 return NULL;
592 if (result != NULL)
593 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000594
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000595 it = PyObject_GetIter(seq);
596 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000597 if (PyErr_ExceptionMatches(PyExc_TypeError))
598 PyErr_SetString(PyExc_TypeError,
599 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000600 Py_XDECREF(result);
601 return NULL;
602 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000603
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000604 if ((args = PyTuple_New(2)) == NULL)
605 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000606
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000607 for (;;) {
608 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000609
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000610 if (args->ob_refcnt > 1) {
611 Py_DECREF(args);
612 if ((args = PyTuple_New(2)) == NULL)
613 goto Fail;
614 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000615
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000616 op2 = PyIter_Next(it);
617 if (op2 == NULL) {
618 if (PyErr_Occurred())
619 goto Fail;
620 break;
621 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000622
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000623 if (result == NULL)
624 result = op2;
625 else {
626 PyTuple_SetItem(args, 0, result);
627 PyTuple_SetItem(args, 1, op2);
628 if ((result = PyEval_CallObject(func, args)) == NULL)
629 goto Fail;
630 }
631 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000632
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000633 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000634
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000635 if (result == NULL)
636 PyErr_SetString(PyExc_TypeError,
637 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000638
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000639 Py_DECREF(it);
640 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000641
642Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000643 Py_XDECREF(args);
644 Py_XDECREF(result);
645 Py_DECREF(it);
646 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000647}
648
649PyDoc_STRVAR(functools_reduce_doc,
650"reduce(function, sequence[, initial]) -> value\n\
651\n\
652Apply a function of two arguments cumulatively to the items of a sequence,\n\
653from left to right, so as to reduce the sequence to a single value.\n\
654For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
655((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
656of the sequence in the calculation, and serves as a default when the\n\
657sequence is empty.");
658
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300659/* lru_cache object **********************************************************/
660
661/* this object is used delimit args and keywords in the cache keys */
662static PyObject *kwd_mark = NULL;
663
664struct lru_list_elem;
665struct lru_cache_object;
666
667typedef struct lru_list_elem {
668 PyObject_HEAD
669 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300670 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300671 PyObject *key, *result;
672} lru_list_elem;
673
674static void
675lru_list_elem_dealloc(lru_list_elem *link)
676{
677 _PyObject_GC_UNTRACK(link);
678 Py_XDECREF(link->key);
679 Py_XDECREF(link->result);
680 PyObject_GC_Del(link);
681}
682
683static int
684lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
685{
686 Py_VISIT(link->key);
687 Py_VISIT(link->result);
688 return 0;
689}
690
691static int
692lru_list_elem_clear(lru_list_elem *link)
693{
694 Py_CLEAR(link->key);
695 Py_CLEAR(link->result);
696 return 0;
697}
698
699static PyTypeObject lru_list_elem_type = {
700 PyVarObject_HEAD_INIT(&PyType_Type, 0)
701 "functools._lru_list_elem", /* tp_name */
702 sizeof(lru_list_elem), /* tp_basicsize */
703 0, /* tp_itemsize */
704 /* methods */
705 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
706 0, /* tp_print */
707 0, /* tp_getattr */
708 0, /* tp_setattr */
709 0, /* tp_reserved */
710 0, /* tp_repr */
711 0, /* tp_as_number */
712 0, /* tp_as_sequence */
713 0, /* tp_as_mapping */
714 0, /* tp_hash */
715 0, /* tp_call */
716 0, /* tp_str */
717 0, /* tp_getattro */
718 0, /* tp_setattro */
719 0, /* tp_as_buffer */
720 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
721 0, /* tp_doc */
722 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
723 (inquiry)lru_list_elem_clear, /* tp_clear */
724};
725
726
727typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
728
729typedef struct lru_cache_object {
730 lru_list_elem root; /* includes PyObject_HEAD */
731 Py_ssize_t maxsize;
732 PyObject *maxsize_O;
733 PyObject *func;
734 lru_cache_ternaryfunc wrapper;
735 PyObject *cache;
736 PyObject *cache_info_type;
737 Py_ssize_t misses, hits;
738 int typed;
739 PyObject *dict;
740 int full;
741} lru_cache_object;
742
743static PyTypeObject lru_cache_type;
744
745static PyObject *
746lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
747{
Raymond Hettingerdda44682017-01-08 18:04:30 -0800748 PyObject *key, *keyword, *value;
749 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300750
751 /* short path, key will match args anyway, which is a tuple */
752 if (!typed && !kwds) {
753 Py_INCREF(args);
754 return args;
755 }
756
Raymond Hettingerdda44682017-01-08 18:04:30 -0800757 kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
758 assert(kwds_size >= 0);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300759
760 key_size = PyTuple_GET_SIZE(args);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800761 if (kwds_size)
762 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300763 if (typed)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800764 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300765
766 key = PyTuple_New(key_size);
767 if (key == NULL)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800768 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300769
770 key_pos = 0;
771 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
772 PyObject *item = PyTuple_GET_ITEM(args, pos);
773 Py_INCREF(item);
774 PyTuple_SET_ITEM(key, key_pos++, item);
775 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800776 if (kwds_size) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300777 Py_INCREF(kwd_mark);
778 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800779 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
780 Py_INCREF(keyword);
781 PyTuple_SET_ITEM(key, key_pos++, keyword);
782 Py_INCREF(value);
783 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300784 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800785 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300786 }
787 if (typed) {
788 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
789 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
790 Py_INCREF(item);
791 PyTuple_SET_ITEM(key, key_pos++, item);
792 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800793 if (kwds_size) {
794 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
795 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300796 Py_INCREF(item);
797 PyTuple_SET_ITEM(key, key_pos++, item);
798 }
799 }
800 }
801 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300802 return key;
803}
804
805static PyObject *
806uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
807{
808 PyObject *result = PyObject_Call(self->func, args, kwds);
809 if (!result)
810 return NULL;
811 self->misses++;
812 return result;
813}
814
815static PyObject *
816infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
817{
818 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300819 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300820 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
821 if (!key)
822 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300823 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500824 if (hash == -1) {
825 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300826 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500827 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300828 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300829 if (result) {
830 Py_INCREF(result);
831 self->hits++;
832 Py_DECREF(key);
833 return result;
834 }
835 if (PyErr_Occurred()) {
836 Py_DECREF(key);
837 return NULL;
838 }
839 result = PyObject_Call(self->func, args, kwds);
840 if (!result) {
841 Py_DECREF(key);
842 return NULL;
843 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300844 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300845 Py_DECREF(result);
846 Py_DECREF(key);
847 return NULL;
848 }
849 Py_DECREF(key);
850 self->misses++;
851 return result;
852}
853
854static void
855lru_cache_extricate_link(lru_list_elem *link)
856{
857 link->prev->next = link->next;
858 link->next->prev = link->prev;
859}
860
861static void
862lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
863{
864 lru_list_elem *root = &self->root;
865 lru_list_elem *last = root->prev;
866 last->next = root->prev = link;
867 link->prev = last;
868 link->next = root;
869}
870
871static PyObject *
872bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
873{
874 lru_list_elem *link;
875 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300876 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300877
878 key = lru_cache_make_key(args, kwds, self->typed);
879 if (!key)
880 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300881 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500882 if (hash == -1) {
883 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300884 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500885 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300886 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300887 if (link) {
888 lru_cache_extricate_link(link);
889 lru_cache_append_link(self, link);
890 self->hits++;
891 result = link->result;
892 Py_INCREF(result);
893 Py_DECREF(key);
894 return result;
895 }
896 if (PyErr_Occurred()) {
897 Py_DECREF(key);
898 return NULL;
899 }
900 result = PyObject_Call(self->func, args, kwds);
901 if (!result) {
902 Py_DECREF(key);
903 return NULL;
904 }
905 if (self->full && self->root.next != &self->root) {
906 /* Use the oldest item to store the new key and result. */
Serhiy Storchaka67796522017-01-12 18:34:33 +0200907 PyObject *oldkey, *oldresult, *popresult;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300908 /* Extricate the oldest item. */
909 link = self->root.next;
910 lru_cache_extricate_link(link);
911 /* Remove it from the cache.
912 The cache dict holds one reference to the link,
913 and the linked list holds yet one reference to it. */
Serhiy Storchaka42e1ea92017-01-12 19:12:21 +0200914 popresult = _PyDict_Pop_KnownHash(self->cache,
Serhiy Storchaka67796522017-01-12 18:34:33 +0200915 link->key, link->hash,
916 Py_None);
917 if (popresult == Py_None) {
918 /* Getting here means that this same key was added to the
919 cache while the lock was released. Since the link
920 update is already done, we need only return the
921 computed result and update the count of misses. */
922 Py_DECREF(popresult);
923 Py_DECREF(link);
924 Py_DECREF(key);
925 }
926 else if (popresult == NULL) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300927 lru_cache_append_link(self, link);
928 Py_DECREF(key);
929 Py_DECREF(result);
930 return NULL;
931 }
Serhiy Storchaka67796522017-01-12 18:34:33 +0200932 else {
933 Py_DECREF(popresult);
934 /* Keep a reference to the old key and old result to
935 prevent their ref counts from going to zero during the
936 update. That will prevent potentially arbitrary object
937 clean-up code (i.e. __del__) from running while we're
938 still adjusting the links. */
939 oldkey = link->key;
940 oldresult = link->result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300941
Serhiy Storchaka67796522017-01-12 18:34:33 +0200942 link->hash = hash;
943 link->key = key;
944 link->result = result;
945 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
946 hash) < 0) {
947 Py_DECREF(link);
948 Py_DECREF(oldkey);
949 Py_DECREF(oldresult);
950 return NULL;
951 }
952 lru_cache_append_link(self, link);
953 Py_INCREF(result); /* for return */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300954 Py_DECREF(oldkey);
955 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300956 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300957 } else {
958 /* Put result in a new link at the front of the queue. */
959 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
960 &lru_list_elem_type);
961 if (link == NULL) {
962 Py_DECREF(key);
963 Py_DECREF(result);
964 return NULL;
965 }
966
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300967 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300968 link->key = key;
969 link->result = result;
970 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300971 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
972 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300973 Py_DECREF(link);
974 return NULL;
975 }
976 lru_cache_append_link(self, link);
977 Py_INCREF(result); /* for return */
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200978 self->full = (PyDict_GET_SIZE(self->cache) >= self->maxsize);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300979 }
980 self->misses++;
981 return result;
982}
983
984static PyObject *
985lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
986{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300987 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300988 int typed;
989 lru_cache_object *obj;
990 Py_ssize_t maxsize;
991 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
992 static char *keywords[] = {"user_function", "maxsize", "typed",
993 "cache_info_type", NULL};
994
995 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
996 &func, &maxsize_O, &typed,
997 &cache_info_type)) {
998 return NULL;
999 }
1000
1001 if (!PyCallable_Check(func)) {
1002 PyErr_SetString(PyExc_TypeError,
1003 "the first argument must be callable");
1004 return NULL;
1005 }
1006
1007 /* select the caching function, and make/inc maxsize_O */
1008 if (maxsize_O == Py_None) {
1009 wrapper = infinite_lru_cache_wrapper;
1010 /* use this only to initialize lru_cache_object attribute maxsize */
1011 maxsize = -1;
1012 } else if (PyIndex_Check(maxsize_O)) {
1013 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1014 if (maxsize == -1 && PyErr_Occurred())
1015 return NULL;
1016 if (maxsize == 0)
1017 wrapper = uncached_lru_cache_wrapper;
1018 else
1019 wrapper = bounded_lru_cache_wrapper;
1020 } else {
1021 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1022 return NULL;
1023 }
1024
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001025 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001026 return NULL;
1027
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001028 obj = (lru_cache_object *)type->tp_alloc(type, 0);
1029 if (obj == NULL) {
1030 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001031 return NULL;
1032 }
1033
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001034 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001035 obj->root.prev = &obj->root;
1036 obj->root.next = &obj->root;
1037 obj->maxsize = maxsize;
1038 Py_INCREF(maxsize_O);
1039 obj->maxsize_O = maxsize_O;
1040 Py_INCREF(func);
1041 obj->func = func;
1042 obj->wrapper = wrapper;
1043 obj->misses = obj->hits = 0;
1044 obj->typed = typed;
1045 Py_INCREF(cache_info_type);
1046 obj->cache_info_type = cache_info_type;
1047
1048 return (PyObject *)obj;
1049}
1050
1051static lru_list_elem *
1052lru_cache_unlink_list(lru_cache_object *self)
1053{
1054 lru_list_elem *root = &self->root;
1055 lru_list_elem *link = root->next;
1056 if (link == root)
1057 return NULL;
1058 root->prev->next = NULL;
1059 root->next = root->prev = root;
1060 return link;
1061}
1062
1063static void
1064lru_cache_clear_list(lru_list_elem *link)
1065{
1066 while (link != NULL) {
1067 lru_list_elem *next = link->next;
1068 Py_DECREF(link);
1069 link = next;
1070 }
1071}
1072
1073static void
1074lru_cache_dealloc(lru_cache_object *obj)
1075{
1076 lru_list_elem *list = lru_cache_unlink_list(obj);
1077 Py_XDECREF(obj->maxsize_O);
1078 Py_XDECREF(obj->func);
1079 Py_XDECREF(obj->cache);
1080 Py_XDECREF(obj->dict);
1081 Py_XDECREF(obj->cache_info_type);
1082 lru_cache_clear_list(list);
1083 Py_TYPE(obj)->tp_free(obj);
1084}
1085
1086static PyObject *
1087lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1088{
1089 return self->wrapper(self, args, kwds);
1090}
1091
1092static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001093lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1094{
1095 if (obj == Py_None || obj == NULL) {
1096 Py_INCREF(self);
1097 return self;
1098 }
1099 return PyMethod_New(self, obj);
1100}
1101
1102static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001103lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1104{
1105 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1106 self->hits, self->misses, self->maxsize_O,
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +02001107 PyDict_GET_SIZE(self->cache));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001108}
1109
1110static PyObject *
1111lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1112{
1113 lru_list_elem *list = lru_cache_unlink_list(self);
1114 self->hits = self->misses = 0;
1115 self->full = 0;
1116 PyDict_Clear(self->cache);
1117 lru_cache_clear_list(list);
1118 Py_RETURN_NONE;
1119}
1120
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001121static PyObject *
1122lru_cache_reduce(PyObject *self, PyObject *unused)
1123{
1124 return PyObject_GetAttrString(self, "__qualname__");
1125}
1126
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001127static PyObject *
1128lru_cache_copy(PyObject *self, PyObject *unused)
1129{
1130 Py_INCREF(self);
1131 return self;
1132}
1133
1134static PyObject *
1135lru_cache_deepcopy(PyObject *self, PyObject *unused)
1136{
1137 Py_INCREF(self);
1138 return self;
1139}
1140
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001141static int
1142lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1143{
1144 lru_list_elem *link = self->root.next;
1145 while (link != &self->root) {
1146 lru_list_elem *next = link->next;
1147 Py_VISIT(link);
1148 link = next;
1149 }
1150 Py_VISIT(self->maxsize_O);
1151 Py_VISIT(self->func);
1152 Py_VISIT(self->cache);
1153 Py_VISIT(self->cache_info_type);
1154 Py_VISIT(self->dict);
1155 return 0;
1156}
1157
1158static int
1159lru_cache_tp_clear(lru_cache_object *self)
1160{
1161 lru_list_elem *list = lru_cache_unlink_list(self);
1162 Py_CLEAR(self->maxsize_O);
1163 Py_CLEAR(self->func);
1164 Py_CLEAR(self->cache);
1165 Py_CLEAR(self->cache_info_type);
1166 Py_CLEAR(self->dict);
1167 lru_cache_clear_list(list);
1168 return 0;
1169}
1170
1171
1172PyDoc_STRVAR(lru_cache_doc,
1173"Create a cached callable that wraps another function.\n\
1174\n\
1175user_function: the function being cached\n\
1176\n\
1177maxsize: 0 for no caching\n\
1178 None for unlimited cache size\n\
1179 n for a bounded cache\n\
1180\n\
1181typed: False cache f(3) and f(3.0) as identical calls\n\
1182 True cache f(3) and f(3.0) as distinct calls\n\
1183\n\
1184cache_info_type: namedtuple class with the fields:\n\
1185 hits misses currsize maxsize\n"
1186);
1187
1188static PyMethodDef lru_cache_methods[] = {
1189 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1190 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001191 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001192 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1193 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001194 {NULL}
1195};
1196
1197static PyGetSetDef lru_cache_getsetlist[] = {
1198 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1199 {NULL}
1200};
1201
1202static PyTypeObject lru_cache_type = {
1203 PyVarObject_HEAD_INIT(NULL, 0)
1204 "functools._lru_cache_wrapper", /* tp_name */
1205 sizeof(lru_cache_object), /* tp_basicsize */
1206 0, /* tp_itemsize */
1207 /* methods */
1208 (destructor)lru_cache_dealloc, /* tp_dealloc */
1209 0, /* tp_print */
1210 0, /* tp_getattr */
1211 0, /* tp_setattr */
1212 0, /* tp_reserved */
1213 0, /* tp_repr */
1214 0, /* tp_as_number */
1215 0, /* tp_as_sequence */
1216 0, /* tp_as_mapping */
1217 0, /* tp_hash */
1218 (ternaryfunc)lru_cache_call, /* tp_call */
1219 0, /* tp_str */
1220 0, /* tp_getattro */
1221 0, /* tp_setattro */
1222 0, /* tp_as_buffer */
1223 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1224 /* tp_flags */
1225 lru_cache_doc, /* tp_doc */
1226 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1227 (inquiry)lru_cache_tp_clear, /* tp_clear */
1228 0, /* tp_richcompare */
1229 0, /* tp_weaklistoffset */
1230 0, /* tp_iter */
1231 0, /* tp_iternext */
1232 lru_cache_methods, /* tp_methods */
1233 0, /* tp_members */
1234 lru_cache_getsetlist, /* tp_getset */
1235 0, /* tp_base */
1236 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001237 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001238 0, /* tp_descr_set */
1239 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1240 0, /* tp_init */
1241 0, /* tp_alloc */
1242 lru_cache_new, /* tp_new */
1243};
1244
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001245/* module level code ********************************************************/
1246
1247PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001248"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001249
1250static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001251 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001252 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1253 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001254 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001255};
1256
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001257static void
1258module_free(void *m)
1259{
1260 Py_CLEAR(kwd_mark);
1261}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001262
1263static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001264 PyModuleDef_HEAD_INIT,
1265 "_functools",
1266 module_doc,
1267 -1,
1268 module_methods,
1269 NULL,
1270 NULL,
1271 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001272 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001273};
1274
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001275PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001276PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001277{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001278 int i;
1279 PyObject *m;
1280 char *name;
1281 PyTypeObject *typelist[] = {
1282 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001283 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001284 NULL
1285 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001286
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001287 m = PyModule_Create(&_functoolsmodule);
1288 if (m == NULL)
1289 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001290
Victor Stinnera5ed5f02016-12-06 18:45:50 +01001291 kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001292 if (!kwd_mark) {
1293 Py_DECREF(m);
1294 return NULL;
1295 }
1296
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001297 for (i=0 ; typelist[i] != NULL ; i++) {
1298 if (PyType_Ready(typelist[i]) < 0) {
1299 Py_DECREF(m);
1300 return NULL;
1301 }
1302 name = strchr(typelist[i]->tp_name, '.');
1303 assert (name != NULL);
1304 Py_INCREF(typelist[i]);
1305 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1306 }
1307 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001308}