blob: 592edbb61404594adaa1159375307a6c4487c5c0 [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 Storchaka38741282016-02-02 18:45:17 +020069 if (pargs == NULL || PyTuple_GET_SIZE(pargs) == 0) {
Alexander Belopolskye49af342015-03-01 15:08:17 -050070 pto->args = nargs;
71 Py_INCREF(nargs);
72 }
73 else if (PyTuple_GET_SIZE(nargs) == 0) {
74 pto->args = pargs;
75 Py_INCREF(pargs);
76 }
77 else {
78 pto->args = PySequence_Concat(pargs, nargs);
79 if (pto->args == NULL) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020080 Py_DECREF(nargs);
Alexander Belopolskye49af342015-03-01 15:08:17 -050081 Py_DECREF(pto);
82 return NULL;
83 }
Serhiy Storchaka38741282016-02-02 18:45:17 +020084 assert(PyTuple_Check(pto->args));
Alexander Belopolskye49af342015-03-01 15:08:17 -050085 }
86 Py_DECREF(nargs);
87
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +020088 if (pkw == NULL || PyDict_GET_SIZE(pkw) == 0) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020089 if (kw == NULL) {
90 pto->kw = PyDict_New();
Alexander Belopolskye49af342015-03-01 15:08:17 -050091 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +020092 else if (Py_REFCNT(kw) == 1) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020093 Py_INCREF(kw);
94 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000095 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +020096 else {
97 pto->kw = PyDict_Copy(kw);
98 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050099 }
100 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200101 pto->kw = PyDict_Copy(pkw);
102 if (kw != NULL && pto->kw != NULL) {
103 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -0400104 Py_DECREF(pto);
105 return NULL;
106 }
107 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000108 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200109 if (pto->kw == NULL) {
110 Py_DECREF(pto);
111 return NULL;
112 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000113
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100114 pto->use_fastcall = _PyObject_HasFastCall(func);
115
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000116 return (PyObject *)pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000117}
118
119static void
120partial_dealloc(partialobject *pto)
121{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000122 PyObject_GC_UnTrack(pto);
123 if (pto->weakreflist != NULL)
124 PyObject_ClearWeakRefs((PyObject *) pto);
125 Py_XDECREF(pto->fn);
126 Py_XDECREF(pto->args);
127 Py_XDECREF(pto->kw);
128 Py_XDECREF(pto->dict);
129 Py_TYPE(pto)->tp_free(pto);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000130}
131
132static PyObject *
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100133partial_fastcall(partialobject *pto, PyObject **args, Py_ssize_t nargs,
134 PyObject *kwargs)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000135{
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100136 PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 PyObject *ret;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100138 PyObject **stack, **stack_buf = NULL;
139 Py_ssize_t nargs2, pto_nargs;
140
141 pto_nargs = PyTuple_GET_SIZE(pto->args);
142 nargs2 = pto_nargs + nargs;
143
144 if (pto_nargs == 0) {
145 stack = args;
146 }
147 else if (nargs == 0) {
148 stack = &PyTuple_GET_ITEM(pto->args, 0);
149 }
150 else {
151 if (nargs2 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
152 stack = small_stack;
153 }
154 else {
155 stack_buf = PyMem_Malloc(nargs2 * sizeof(PyObject *));
156 if (stack_buf == NULL) {
157 PyErr_NoMemory();
158 return NULL;
159 }
160 stack = stack_buf;
161 }
162
163 /* use borrowed references */
164 memcpy(stack,
165 &PyTuple_GET_ITEM(pto->args, 0),
166 pto_nargs * sizeof(PyObject*));
167 memcpy(&stack[pto_nargs],
168 args,
169 nargs * sizeof(PyObject*));
170 }
171
172 ret = _PyObject_FastCallDict(pto->fn, stack, nargs2, kwargs);
173 PyMem_Free(stack_buf);
174 return ret;
175}
176
177static PyObject *
178partial_call_impl(partialobject *pto, PyObject *args, PyObject *kwargs)
179{
180 PyObject *ret, *args2;
181
182 /* Note: tupleconcat() is optimized for empty tuples */
183 args2 = PySequence_Concat(pto->args, args);
184 if (args2 == NULL) {
185 return NULL;
186 }
187 assert(PyTuple_Check(args2));
188
189 ret = PyObject_Call(pto->fn, args2, kwargs);
190 Py_DECREF(args2);
191 return ret;
192}
193
194static PyObject *
195partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
196{
197 PyObject *kwargs2, *res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000198
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000199 assert (PyCallable_Check(pto->fn));
200 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200201 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000202
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200203 if (PyDict_GET_SIZE(pto->kw) == 0) {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100204 /* kwargs can be NULL */
205 kwargs2 = kwargs;
206 Py_XINCREF(kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200207 }
208 else {
Victor Stinner561ca802017-02-23 18:26:43 +0100209 /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
210 copied, because a function using "**kwargs" can modify the
211 dictionary. */
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100212 kwargs2 = PyDict_Copy(pto->kw);
213 if (kwargs2 == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214 return NULL;
215 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200216
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100217 if (kwargs != NULL) {
218 if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
219 Py_DECREF(kwargs2);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000220 return NULL;
221 }
222 }
223 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000224
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100225
226 if (pto->use_fastcall) {
227 res = partial_fastcall(pto,
228 &PyTuple_GET_ITEM(args, 0),
229 PyTuple_GET_SIZE(args),
230 kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200231 }
232 else {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100233 res = partial_call_impl(pto, args, kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200234 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100235 Py_XDECREF(kwargs2);
236 return res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000237}
238
239static int
240partial_traverse(partialobject *pto, visitproc visit, void *arg)
241{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 Py_VISIT(pto->fn);
243 Py_VISIT(pto->args);
244 Py_VISIT(pto->kw);
245 Py_VISIT(pto->dict);
246 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000247}
248
249PyDoc_STRVAR(partial_doc,
250"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000251 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000252
253#define OFF(x) offsetof(partialobject, x)
254static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000255 {"func", T_OBJECT, OFF(fn), READONLY,
256 "function object to use in future partial calls"},
257 {"args", T_OBJECT, OFF(args), READONLY,
258 "tuple of arguments to future partial calls"},
259 {"keywords", T_OBJECT, OFF(kw), READONLY,
260 "dictionary of keyword arguments to future partial calls"},
261 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000262};
263
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000264static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500265 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000267};
268
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000269static PyObject *
270partial_repr(partialobject *pto)
271{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300272 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000273 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000274 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200275 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300276 int status;
277
278 status = Py_ReprEnter((PyObject *)pto);
279 if (status != 0) {
280 if (status < 0)
281 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000282 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300283 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000284
285 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300286 if (arglist == NULL)
287 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000288 /* Pack positional arguments */
289 assert (PyTuple_Check(pto->args));
290 n = PyTuple_GET_SIZE(pto->args);
291 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300292 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
293 PyTuple_GET_ITEM(pto->args, i)));
294 if (arglist == NULL)
295 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000296 }
297 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200298 assert (PyDict_Check(pto->kw));
299 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Michael Seifert6c3d5272017-03-15 06:26:33 +0100300 /* Prevent key.__str__ from deleting the value. */
301 Py_INCREF(value);
302 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300303 key, value));
Michael Seifert6c3d5272017-03-15 06:26:33 +0100304 Py_DECREF(value);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300305 if (arglist == NULL)
306 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000307 }
308 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
309 pto->fn, arglist);
310 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300311
312 done:
313 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000314 return result;
315}
316
Jack Diederiche0cbd692009-04-01 04:27:09 +0000317/* Pickle strategy:
318 __reduce__ by itself doesn't support getting kwargs in the unpickle
319 operation so we define a __setstate__ that replaces all the information
320 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200321 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000322 */
323
Antoine Pitrou69f71142009-05-24 21:25:49 +0000324static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000325partial_reduce(partialobject *pto, PyObject *unused)
326{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
328 pto->args, pto->kw,
329 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000330}
331
Antoine Pitrou69f71142009-05-24 21:25:49 +0000332static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200333partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000334{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000335 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200336
337 if (!PyTuple_Check(state) ||
338 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
339 !PyCallable_Check(fn) ||
340 !PyTuple_Check(fnargs) ||
341 (kw != Py_None && !PyDict_Check(kw)))
342 {
343 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000344 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000345 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200346
347 if(!PyTuple_CheckExact(fnargs))
348 fnargs = PySequence_Tuple(fnargs);
349 else
350 Py_INCREF(fnargs);
351 if (fnargs == NULL)
352 return NULL;
353
354 if (kw == Py_None)
355 kw = PyDict_New();
356 else if(!PyDict_CheckExact(kw))
357 kw = PyDict_Copy(kw);
358 else
359 Py_INCREF(kw);
360 if (kw == NULL) {
361 Py_DECREF(fnargs);
362 return NULL;
363 }
364
Serhiy Storchaka38741282016-02-02 18:45:17 +0200365 if (dict == Py_None)
366 dict = NULL;
367 else
368 Py_INCREF(dict);
369
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100370 Py_INCREF(fn);
371 pto->use_fastcall = _PyObject_HasFastCall(fn);
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300372 Py_SETREF(pto->fn, fn);
373 Py_SETREF(pto->args, fnargs);
374 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300375 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000376 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000377}
378
379static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000380 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200381 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000383};
384
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000385static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 PyVarObject_HEAD_INIT(NULL, 0)
387 "functools.partial", /* tp_name */
388 sizeof(partialobject), /* tp_basicsize */
389 0, /* tp_itemsize */
390 /* methods */
391 (destructor)partial_dealloc, /* tp_dealloc */
392 0, /* tp_print */
393 0, /* tp_getattr */
394 0, /* tp_setattr */
395 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000396 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 0, /* tp_as_number */
398 0, /* tp_as_sequence */
399 0, /* tp_as_mapping */
400 0, /* tp_hash */
401 (ternaryfunc)partial_call, /* tp_call */
402 0, /* tp_str */
403 PyObject_GenericGetAttr, /* tp_getattro */
404 PyObject_GenericSetAttr, /* tp_setattro */
405 0, /* tp_as_buffer */
406 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
407 Py_TPFLAGS_BASETYPE, /* tp_flags */
408 partial_doc, /* tp_doc */
409 (traverseproc)partial_traverse, /* tp_traverse */
410 0, /* tp_clear */
411 0, /* tp_richcompare */
412 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
413 0, /* tp_iter */
414 0, /* tp_iternext */
415 partial_methods, /* tp_methods */
416 partial_memberlist, /* tp_members */
417 partial_getsetlist, /* tp_getset */
418 0, /* tp_base */
419 0, /* tp_dict */
420 0, /* tp_descr_get */
421 0, /* tp_descr_set */
422 offsetof(partialobject, dict), /* tp_dictoffset */
423 0, /* tp_init */
424 0, /* tp_alloc */
425 partial_new, /* tp_new */
426 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000427};
428
429
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700430/* cmp_to_key ***************************************************************/
431
432typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200433 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700434 PyObject *cmp;
435 PyObject *object;
436} keyobject;
437
438static void
439keyobject_dealloc(keyobject *ko)
440{
441 Py_DECREF(ko->cmp);
442 Py_XDECREF(ko->object);
443 PyObject_FREE(ko);
444}
445
446static int
447keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
448{
449 Py_VISIT(ko->cmp);
450 if (ko->object)
451 Py_VISIT(ko->object);
452 return 0;
453}
454
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500455static int
456keyobject_clear(keyobject *ko)
457{
458 Py_CLEAR(ko->cmp);
459 if (ko->object)
460 Py_CLEAR(ko->object);
461 return 0;
462}
463
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700464static PyMemberDef keyobject_members[] = {
465 {"obj", T_OBJECT,
466 offsetof(keyobject, object), 0,
467 PyDoc_STR("Value wrapped by a key function.")},
468 {NULL}
469};
470
471static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700472keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700473
474static PyObject *
475keyobject_richcompare(PyObject *ko, PyObject *other, int op);
476
477static PyTypeObject keyobject_type = {
478 PyVarObject_HEAD_INIT(&PyType_Type, 0)
479 "functools.KeyWrapper", /* tp_name */
480 sizeof(keyobject), /* tp_basicsize */
481 0, /* tp_itemsize */
482 /* methods */
483 (destructor)keyobject_dealloc, /* tp_dealloc */
484 0, /* tp_print */
485 0, /* tp_getattr */
486 0, /* tp_setattr */
487 0, /* tp_reserved */
488 0, /* tp_repr */
489 0, /* tp_as_number */
490 0, /* tp_as_sequence */
491 0, /* tp_as_mapping */
492 0, /* tp_hash */
493 (ternaryfunc)keyobject_call, /* tp_call */
494 0, /* tp_str */
495 PyObject_GenericGetAttr, /* tp_getattro */
496 0, /* tp_setattro */
497 0, /* tp_as_buffer */
498 Py_TPFLAGS_DEFAULT, /* tp_flags */
499 0, /* tp_doc */
500 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500501 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700502 keyobject_richcompare, /* tp_richcompare */
503 0, /* tp_weaklistoffset */
504 0, /* tp_iter */
505 0, /* tp_iternext */
506 0, /* tp_methods */
507 keyobject_members, /* tp_members */
508 0, /* tp_getset */
509};
510
511static PyObject *
512keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
513{
514 PyObject *object;
515 keyobject *result;
516 static char *kwargs[] = {"obj", NULL};
517
518 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
519 return NULL;
520 result = PyObject_New(keyobject, &keyobject_type);
521 if (!result)
522 return NULL;
523 Py_INCREF(ko->cmp);
524 result->cmp = ko->cmp;
525 Py_INCREF(object);
526 result->object = object;
527 return (PyObject *)result;
528}
529
530static PyObject *
531keyobject_richcompare(PyObject *ko, PyObject *other, int op)
532{
533 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700534 PyObject *x;
535 PyObject *y;
536 PyObject *compare;
537 PyObject *answer;
538 static PyObject *zero;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200539 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700540
541 if (zero == NULL) {
542 zero = PyLong_FromLong(0);
543 if (!zero)
544 return NULL;
545 }
546
547 if (Py_TYPE(other) != &keyobject_type){
548 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
549 return NULL;
550 }
551 compare = ((keyobject *) ko)->cmp;
552 assert(compare != NULL);
553 x = ((keyobject *) ko)->object;
554 y = ((keyobject *) other)->object;
555 if (!x || !y){
556 PyErr_Format(PyExc_AttributeError, "object");
557 return NULL;
558 }
559
560 /* Call the user's comparison function and translate the 3-way
561 * result into true or false (or error).
562 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200563 stack[0] = x;
564 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200565 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200566 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700567 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200568 }
569
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700570 answer = PyObject_RichCompare(res, zero, op);
571 Py_DECREF(res);
572 return answer;
573}
574
575static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200576functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
577{
578 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700579 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200580 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700581
582 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
583 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200584 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700585 if (!object)
586 return NULL;
587 Py_INCREF(cmp);
588 object->cmp = cmp;
589 object->object = NULL;
590 return (PyObject *)object;
591}
592
593PyDoc_STRVAR(functools_cmp_to_key_doc,
594"Convert a cmp= function into a key= function.");
595
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000596/* reduce (used to be a builtin) ********************************************/
597
598static PyObject *
599functools_reduce(PyObject *self, PyObject *args)
600{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000601 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000602
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000603 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
604 return NULL;
605 if (result != NULL)
606 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000607
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000608 it = PyObject_GetIter(seq);
609 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000610 if (PyErr_ExceptionMatches(PyExc_TypeError))
611 PyErr_SetString(PyExc_TypeError,
612 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000613 Py_XDECREF(result);
614 return NULL;
615 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000616
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000617 if ((args = PyTuple_New(2)) == NULL)
618 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000619
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000620 for (;;) {
621 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000622
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000623 if (args->ob_refcnt > 1) {
624 Py_DECREF(args);
625 if ((args = PyTuple_New(2)) == NULL)
626 goto Fail;
627 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000628
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000629 op2 = PyIter_Next(it);
630 if (op2 == NULL) {
631 if (PyErr_Occurred())
632 goto Fail;
633 break;
634 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000635
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000636 if (result == NULL)
637 result = op2;
638 else {
639 PyTuple_SetItem(args, 0, result);
640 PyTuple_SetItem(args, 1, op2);
641 if ((result = PyEval_CallObject(func, args)) == NULL)
642 goto Fail;
643 }
644 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000645
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000646 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000647
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000648 if (result == NULL)
649 PyErr_SetString(PyExc_TypeError,
650 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000651
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000652 Py_DECREF(it);
653 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000654
655Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000656 Py_XDECREF(args);
657 Py_XDECREF(result);
658 Py_DECREF(it);
659 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000660}
661
662PyDoc_STRVAR(functools_reduce_doc,
663"reduce(function, sequence[, initial]) -> value\n\
664\n\
665Apply a function of two arguments cumulatively to the items of a sequence,\n\
666from left to right, so as to reduce the sequence to a single value.\n\
667For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
668((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
669of the sequence in the calculation, and serves as a default when the\n\
670sequence is empty.");
671
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300672/* lru_cache object **********************************************************/
673
674/* this object is used delimit args and keywords in the cache keys */
675static PyObject *kwd_mark = NULL;
676
677struct lru_list_elem;
678struct lru_cache_object;
679
680typedef struct lru_list_elem {
681 PyObject_HEAD
682 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300683 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300684 PyObject *key, *result;
685} lru_list_elem;
686
687static void
688lru_list_elem_dealloc(lru_list_elem *link)
689{
690 _PyObject_GC_UNTRACK(link);
691 Py_XDECREF(link->key);
692 Py_XDECREF(link->result);
693 PyObject_GC_Del(link);
694}
695
696static int
697lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
698{
699 Py_VISIT(link->key);
700 Py_VISIT(link->result);
701 return 0;
702}
703
704static int
705lru_list_elem_clear(lru_list_elem *link)
706{
707 Py_CLEAR(link->key);
708 Py_CLEAR(link->result);
709 return 0;
710}
711
712static PyTypeObject lru_list_elem_type = {
713 PyVarObject_HEAD_INIT(&PyType_Type, 0)
714 "functools._lru_list_elem", /* tp_name */
715 sizeof(lru_list_elem), /* tp_basicsize */
716 0, /* tp_itemsize */
717 /* methods */
718 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
719 0, /* tp_print */
720 0, /* tp_getattr */
721 0, /* tp_setattr */
722 0, /* tp_reserved */
723 0, /* tp_repr */
724 0, /* tp_as_number */
725 0, /* tp_as_sequence */
726 0, /* tp_as_mapping */
727 0, /* tp_hash */
728 0, /* tp_call */
729 0, /* tp_str */
730 0, /* tp_getattro */
731 0, /* tp_setattro */
732 0, /* tp_as_buffer */
733 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
734 0, /* tp_doc */
735 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
736 (inquiry)lru_list_elem_clear, /* tp_clear */
737};
738
739
740typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
741
742typedef struct lru_cache_object {
743 lru_list_elem root; /* includes PyObject_HEAD */
744 Py_ssize_t maxsize;
745 PyObject *maxsize_O;
746 PyObject *func;
747 lru_cache_ternaryfunc wrapper;
748 PyObject *cache;
749 PyObject *cache_info_type;
750 Py_ssize_t misses, hits;
751 int typed;
752 PyObject *dict;
753 int full;
754} lru_cache_object;
755
756static PyTypeObject lru_cache_type;
757
758static PyObject *
759lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
760{
Raymond Hettingerdda44682017-01-08 18:04:30 -0800761 PyObject *key, *keyword, *value;
762 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300763
764 /* short path, key will match args anyway, which is a tuple */
765 if (!typed && !kwds) {
766 Py_INCREF(args);
767 return args;
768 }
769
Raymond Hettingerdda44682017-01-08 18:04:30 -0800770 kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
771 assert(kwds_size >= 0);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300772
773 key_size = PyTuple_GET_SIZE(args);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800774 if (kwds_size)
775 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300776 if (typed)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800777 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300778
779 key = PyTuple_New(key_size);
780 if (key == NULL)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800781 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300782
783 key_pos = 0;
784 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
785 PyObject *item = PyTuple_GET_ITEM(args, pos);
786 Py_INCREF(item);
787 PyTuple_SET_ITEM(key, key_pos++, item);
788 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800789 if (kwds_size) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300790 Py_INCREF(kwd_mark);
791 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800792 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
793 Py_INCREF(keyword);
794 PyTuple_SET_ITEM(key, key_pos++, keyword);
795 Py_INCREF(value);
796 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300797 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800798 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300799 }
800 if (typed) {
801 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
802 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
803 Py_INCREF(item);
804 PyTuple_SET_ITEM(key, key_pos++, item);
805 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800806 if (kwds_size) {
807 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
808 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300809 Py_INCREF(item);
810 PyTuple_SET_ITEM(key, key_pos++, item);
811 }
812 }
813 }
814 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300815 return key;
816}
817
818static PyObject *
819uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
820{
821 PyObject *result = PyObject_Call(self->func, args, kwds);
822 if (!result)
823 return NULL;
824 self->misses++;
825 return result;
826}
827
828static PyObject *
829infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
830{
831 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300832 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300833 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
834 if (!key)
835 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300836 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500837 if (hash == -1) {
838 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300839 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500840 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300841 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300842 if (result) {
843 Py_INCREF(result);
844 self->hits++;
845 Py_DECREF(key);
846 return result;
847 }
848 if (PyErr_Occurred()) {
849 Py_DECREF(key);
850 return NULL;
851 }
852 result = PyObject_Call(self->func, args, kwds);
853 if (!result) {
854 Py_DECREF(key);
855 return NULL;
856 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300857 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300858 Py_DECREF(result);
859 Py_DECREF(key);
860 return NULL;
861 }
862 Py_DECREF(key);
863 self->misses++;
864 return result;
865}
866
867static void
868lru_cache_extricate_link(lru_list_elem *link)
869{
870 link->prev->next = link->next;
871 link->next->prev = link->prev;
872}
873
874static void
875lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
876{
877 lru_list_elem *root = &self->root;
878 lru_list_elem *last = root->prev;
879 last->next = root->prev = link;
880 link->prev = last;
881 link->next = root;
882}
883
884static PyObject *
885bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
886{
887 lru_list_elem *link;
888 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300889 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300890
891 key = lru_cache_make_key(args, kwds, self->typed);
892 if (!key)
893 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300894 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500895 if (hash == -1) {
896 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300897 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500898 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300899 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300900 if (link) {
901 lru_cache_extricate_link(link);
902 lru_cache_append_link(self, link);
903 self->hits++;
904 result = link->result;
905 Py_INCREF(result);
906 Py_DECREF(key);
907 return result;
908 }
909 if (PyErr_Occurred()) {
910 Py_DECREF(key);
911 return NULL;
912 }
913 result = PyObject_Call(self->func, args, kwds);
914 if (!result) {
915 Py_DECREF(key);
916 return NULL;
917 }
918 if (self->full && self->root.next != &self->root) {
919 /* Use the oldest item to store the new key and result. */
Serhiy Storchaka67796522017-01-12 18:34:33 +0200920 PyObject *oldkey, *oldresult, *popresult;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300921 /* Extricate the oldest item. */
922 link = self->root.next;
923 lru_cache_extricate_link(link);
924 /* Remove it from the cache.
925 The cache dict holds one reference to the link,
926 and the linked list holds yet one reference to it. */
Serhiy Storchaka42e1ea92017-01-12 19:12:21 +0200927 popresult = _PyDict_Pop_KnownHash(self->cache,
Serhiy Storchaka67796522017-01-12 18:34:33 +0200928 link->key, link->hash,
929 Py_None);
930 if (popresult == Py_None) {
931 /* Getting here means that this same key was added to the
932 cache while the lock was released. Since the link
933 update is already done, we need only return the
934 computed result and update the count of misses. */
935 Py_DECREF(popresult);
936 Py_DECREF(link);
937 Py_DECREF(key);
938 }
939 else if (popresult == NULL) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300940 lru_cache_append_link(self, link);
941 Py_DECREF(key);
942 Py_DECREF(result);
943 return NULL;
944 }
Serhiy Storchaka67796522017-01-12 18:34:33 +0200945 else {
946 Py_DECREF(popresult);
947 /* Keep a reference to the old key and old result to
948 prevent their ref counts from going to zero during the
949 update. That will prevent potentially arbitrary object
950 clean-up code (i.e. __del__) from running while we're
951 still adjusting the links. */
952 oldkey = link->key;
953 oldresult = link->result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300954
Serhiy Storchaka67796522017-01-12 18:34:33 +0200955 link->hash = hash;
956 link->key = key;
957 link->result = result;
958 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
959 hash) < 0) {
960 Py_DECREF(link);
961 Py_DECREF(oldkey);
962 Py_DECREF(oldresult);
963 return NULL;
964 }
965 lru_cache_append_link(self, link);
966 Py_INCREF(result); /* for return */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300967 Py_DECREF(oldkey);
968 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300969 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300970 } else {
971 /* Put result in a new link at the front of the queue. */
972 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
973 &lru_list_elem_type);
974 if (link == NULL) {
975 Py_DECREF(key);
976 Py_DECREF(result);
977 return NULL;
978 }
979
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300980 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300981 link->key = key;
982 link->result = result;
983 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300984 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
985 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300986 Py_DECREF(link);
987 return NULL;
988 }
989 lru_cache_append_link(self, link);
990 Py_INCREF(result); /* for return */
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200991 self->full = (PyDict_GET_SIZE(self->cache) >= self->maxsize);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300992 }
993 self->misses++;
994 return result;
995}
996
997static PyObject *
998lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
999{
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001000 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001001 int typed;
1002 lru_cache_object *obj;
1003 Py_ssize_t maxsize;
1004 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
1005 static char *keywords[] = {"user_function", "maxsize", "typed",
1006 "cache_info_type", NULL};
1007
1008 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
1009 &func, &maxsize_O, &typed,
1010 &cache_info_type)) {
1011 return NULL;
1012 }
1013
1014 if (!PyCallable_Check(func)) {
1015 PyErr_SetString(PyExc_TypeError,
1016 "the first argument must be callable");
1017 return NULL;
1018 }
1019
1020 /* select the caching function, and make/inc maxsize_O */
1021 if (maxsize_O == Py_None) {
1022 wrapper = infinite_lru_cache_wrapper;
1023 /* use this only to initialize lru_cache_object attribute maxsize */
1024 maxsize = -1;
1025 } else if (PyIndex_Check(maxsize_O)) {
1026 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1027 if (maxsize == -1 && PyErr_Occurred())
1028 return NULL;
1029 if (maxsize == 0)
1030 wrapper = uncached_lru_cache_wrapper;
1031 else
1032 wrapper = bounded_lru_cache_wrapper;
1033 } else {
1034 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1035 return NULL;
1036 }
1037
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001038 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001039 return NULL;
1040
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001041 obj = (lru_cache_object *)type->tp_alloc(type, 0);
1042 if (obj == NULL) {
1043 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001044 return NULL;
1045 }
1046
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001047 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001048 obj->root.prev = &obj->root;
1049 obj->root.next = &obj->root;
1050 obj->maxsize = maxsize;
1051 Py_INCREF(maxsize_O);
1052 obj->maxsize_O = maxsize_O;
1053 Py_INCREF(func);
1054 obj->func = func;
1055 obj->wrapper = wrapper;
1056 obj->misses = obj->hits = 0;
1057 obj->typed = typed;
1058 Py_INCREF(cache_info_type);
1059 obj->cache_info_type = cache_info_type;
1060
1061 return (PyObject *)obj;
1062}
1063
1064static lru_list_elem *
1065lru_cache_unlink_list(lru_cache_object *self)
1066{
1067 lru_list_elem *root = &self->root;
1068 lru_list_elem *link = root->next;
1069 if (link == root)
1070 return NULL;
1071 root->prev->next = NULL;
1072 root->next = root->prev = root;
1073 return link;
1074}
1075
1076static void
1077lru_cache_clear_list(lru_list_elem *link)
1078{
1079 while (link != NULL) {
1080 lru_list_elem *next = link->next;
1081 Py_DECREF(link);
1082 link = next;
1083 }
1084}
1085
1086static void
1087lru_cache_dealloc(lru_cache_object *obj)
1088{
1089 lru_list_elem *list = lru_cache_unlink_list(obj);
1090 Py_XDECREF(obj->maxsize_O);
1091 Py_XDECREF(obj->func);
1092 Py_XDECREF(obj->cache);
1093 Py_XDECREF(obj->dict);
1094 Py_XDECREF(obj->cache_info_type);
1095 lru_cache_clear_list(list);
1096 Py_TYPE(obj)->tp_free(obj);
1097}
1098
1099static PyObject *
1100lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1101{
1102 return self->wrapper(self, args, kwds);
1103}
1104
1105static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001106lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1107{
1108 if (obj == Py_None || obj == NULL) {
1109 Py_INCREF(self);
1110 return self;
1111 }
1112 return PyMethod_New(self, obj);
1113}
1114
1115static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001116lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1117{
1118 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1119 self->hits, self->misses, self->maxsize_O,
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +02001120 PyDict_GET_SIZE(self->cache));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001121}
1122
1123static PyObject *
1124lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1125{
1126 lru_list_elem *list = lru_cache_unlink_list(self);
1127 self->hits = self->misses = 0;
1128 self->full = 0;
1129 PyDict_Clear(self->cache);
1130 lru_cache_clear_list(list);
1131 Py_RETURN_NONE;
1132}
1133
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001134static PyObject *
1135lru_cache_reduce(PyObject *self, PyObject *unused)
1136{
1137 return PyObject_GetAttrString(self, "__qualname__");
1138}
1139
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001140static PyObject *
1141lru_cache_copy(PyObject *self, PyObject *unused)
1142{
1143 Py_INCREF(self);
1144 return self;
1145}
1146
1147static PyObject *
1148lru_cache_deepcopy(PyObject *self, PyObject *unused)
1149{
1150 Py_INCREF(self);
1151 return self;
1152}
1153
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001154static int
1155lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1156{
1157 lru_list_elem *link = self->root.next;
1158 while (link != &self->root) {
1159 lru_list_elem *next = link->next;
1160 Py_VISIT(link);
1161 link = next;
1162 }
1163 Py_VISIT(self->maxsize_O);
1164 Py_VISIT(self->func);
1165 Py_VISIT(self->cache);
1166 Py_VISIT(self->cache_info_type);
1167 Py_VISIT(self->dict);
1168 return 0;
1169}
1170
1171static int
1172lru_cache_tp_clear(lru_cache_object *self)
1173{
1174 lru_list_elem *list = lru_cache_unlink_list(self);
1175 Py_CLEAR(self->maxsize_O);
1176 Py_CLEAR(self->func);
1177 Py_CLEAR(self->cache);
1178 Py_CLEAR(self->cache_info_type);
1179 Py_CLEAR(self->dict);
1180 lru_cache_clear_list(list);
1181 return 0;
1182}
1183
1184
1185PyDoc_STRVAR(lru_cache_doc,
1186"Create a cached callable that wraps another function.\n\
1187\n\
1188user_function: the function being cached\n\
1189\n\
1190maxsize: 0 for no caching\n\
1191 None for unlimited cache size\n\
1192 n for a bounded cache\n\
1193\n\
1194typed: False cache f(3) and f(3.0) as identical calls\n\
1195 True cache f(3) and f(3.0) as distinct calls\n\
1196\n\
1197cache_info_type: namedtuple class with the fields:\n\
1198 hits misses currsize maxsize\n"
1199);
1200
1201static PyMethodDef lru_cache_methods[] = {
1202 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1203 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001204 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001205 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1206 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001207 {NULL}
1208};
1209
1210static PyGetSetDef lru_cache_getsetlist[] = {
1211 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1212 {NULL}
1213};
1214
1215static PyTypeObject lru_cache_type = {
1216 PyVarObject_HEAD_INIT(NULL, 0)
1217 "functools._lru_cache_wrapper", /* tp_name */
1218 sizeof(lru_cache_object), /* tp_basicsize */
1219 0, /* tp_itemsize */
1220 /* methods */
1221 (destructor)lru_cache_dealloc, /* tp_dealloc */
1222 0, /* tp_print */
1223 0, /* tp_getattr */
1224 0, /* tp_setattr */
1225 0, /* tp_reserved */
1226 0, /* tp_repr */
1227 0, /* tp_as_number */
1228 0, /* tp_as_sequence */
1229 0, /* tp_as_mapping */
1230 0, /* tp_hash */
1231 (ternaryfunc)lru_cache_call, /* tp_call */
1232 0, /* tp_str */
1233 0, /* tp_getattro */
1234 0, /* tp_setattro */
1235 0, /* tp_as_buffer */
1236 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1237 /* tp_flags */
1238 lru_cache_doc, /* tp_doc */
1239 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1240 (inquiry)lru_cache_tp_clear, /* tp_clear */
1241 0, /* tp_richcompare */
1242 0, /* tp_weaklistoffset */
1243 0, /* tp_iter */
1244 0, /* tp_iternext */
1245 lru_cache_methods, /* tp_methods */
1246 0, /* tp_members */
1247 lru_cache_getsetlist, /* tp_getset */
1248 0, /* tp_base */
1249 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001250 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001251 0, /* tp_descr_set */
1252 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1253 0, /* tp_init */
1254 0, /* tp_alloc */
1255 lru_cache_new, /* tp_new */
1256};
1257
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001258/* module level code ********************************************************/
1259
1260PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001261"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001262
1263static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001264 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001265 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1266 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001267 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001268};
1269
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001270static void
1271module_free(void *m)
1272{
1273 Py_CLEAR(kwd_mark);
1274}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001275
1276static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001277 PyModuleDef_HEAD_INIT,
1278 "_functools",
1279 module_doc,
1280 -1,
1281 module_methods,
1282 NULL,
1283 NULL,
1284 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001285 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001286};
1287
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001288PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001289PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001290{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001291 int i;
1292 PyObject *m;
1293 char *name;
1294 PyTypeObject *typelist[] = {
1295 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001296 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001297 NULL
1298 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001299
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001300 m = PyModule_Create(&_functoolsmodule);
1301 if (m == NULL)
1302 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001303
Victor Stinnera5ed5f02016-12-06 18:45:50 +01001304 kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001305 if (!kwd_mark) {
1306 Py_DECREF(m);
1307 return NULL;
1308 }
1309
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001310 for (i=0 ; typelist[i] != NULL ; i++) {
1311 if (PyType_Ready(typelist[i]) < 0) {
1312 Py_DECREF(m);
1313 return NULL;
1314 }
1315 name = strchr(typelist[i]->tp_name, '.');
1316 assert (name != NULL);
1317 Py_INCREF(typelist[i]);
1318 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1319 }
1320 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001321}