blob: 33761a46667dd05b04421cdbd35a89eba8d333ad [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{
INADA Naokia6296d32017-08-24 14:55:17 +0900116 /* bpo-31095: UnTrack is needed before calling any callbacks */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000117 PyObject_GC_UnTrack(pto);
118 if (pto->weakreflist != NULL)
119 PyObject_ClearWeakRefs((PyObject *) pto);
120 Py_XDECREF(pto->fn);
121 Py_XDECREF(pto->args);
122 Py_XDECREF(pto->kw);
123 Py_XDECREF(pto->dict);
124 Py_TYPE(pto)->tp_free(pto);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000125}
126
127static PyObject *
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100128partial_fastcall(partialobject *pto, PyObject **args, Py_ssize_t nargs,
129 PyObject *kwargs)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000130{
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100131 PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 PyObject *ret;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100133 PyObject **stack, **stack_buf = NULL;
134 Py_ssize_t nargs2, pto_nargs;
135
136 pto_nargs = PyTuple_GET_SIZE(pto->args);
137 nargs2 = pto_nargs + nargs;
138
139 if (pto_nargs == 0) {
140 stack = args;
141 }
142 else if (nargs == 0) {
143 stack = &PyTuple_GET_ITEM(pto->args, 0);
144 }
145 else {
146 if (nargs2 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
147 stack = small_stack;
148 }
149 else {
150 stack_buf = PyMem_Malloc(nargs2 * sizeof(PyObject *));
151 if (stack_buf == NULL) {
152 PyErr_NoMemory();
153 return NULL;
154 }
155 stack = stack_buf;
156 }
157
158 /* use borrowed references */
159 memcpy(stack,
160 &PyTuple_GET_ITEM(pto->args, 0),
161 pto_nargs * sizeof(PyObject*));
162 memcpy(&stack[pto_nargs],
163 args,
164 nargs * sizeof(PyObject*));
165 }
166
167 ret = _PyObject_FastCallDict(pto->fn, stack, nargs2, kwargs);
168 PyMem_Free(stack_buf);
169 return ret;
170}
171
172static PyObject *
173partial_call_impl(partialobject *pto, PyObject *args, PyObject *kwargs)
174{
175 PyObject *ret, *args2;
176
177 /* Note: tupleconcat() is optimized for empty tuples */
178 args2 = PySequence_Concat(pto->args, args);
179 if (args2 == NULL) {
180 return NULL;
181 }
182 assert(PyTuple_Check(args2));
183
184 ret = PyObject_Call(pto->fn, args2, kwargs);
185 Py_DECREF(args2);
186 return ret;
187}
188
189static PyObject *
190partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
191{
192 PyObject *kwargs2, *res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000193
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000194 assert (PyCallable_Check(pto->fn));
195 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200196 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000197
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200198 if (PyDict_GET_SIZE(pto->kw) == 0) {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100199 /* kwargs can be NULL */
200 kwargs2 = kwargs;
201 Py_XINCREF(kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200202 }
203 else {
Victor Stinner561ca802017-02-23 18:26:43 +0100204 /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
205 copied, because a function using "**kwargs" can modify the
206 dictionary. */
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100207 kwargs2 = PyDict_Copy(pto->kw);
208 if (kwargs2 == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000209 return NULL;
210 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200211
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100212 if (kwargs != NULL) {
213 if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
214 Py_DECREF(kwargs2);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000215 return NULL;
216 }
217 }
218 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000219
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100220
221 if (pto->use_fastcall) {
222 res = partial_fastcall(pto,
223 &PyTuple_GET_ITEM(args, 0),
224 PyTuple_GET_SIZE(args),
225 kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200226 }
227 else {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100228 res = partial_call_impl(pto, args, kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200229 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100230 Py_XDECREF(kwargs2);
231 return res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000232}
233
234static int
235partial_traverse(partialobject *pto, visitproc visit, void *arg)
236{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000237 Py_VISIT(pto->fn);
238 Py_VISIT(pto->args);
239 Py_VISIT(pto->kw);
240 Py_VISIT(pto->dict);
241 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000242}
243
244PyDoc_STRVAR(partial_doc,
245"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000247
248#define OFF(x) offsetof(partialobject, x)
249static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250 {"func", T_OBJECT, OFF(fn), READONLY,
251 "function object to use in future partial calls"},
252 {"args", T_OBJECT, OFF(args), READONLY,
253 "tuple of arguments to future partial calls"},
254 {"keywords", T_OBJECT, OFF(kw), READONLY,
255 "dictionary of keyword arguments to future partial calls"},
256 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000257};
258
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000259static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500260 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000261 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000262};
263
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000264static PyObject *
265partial_repr(partialobject *pto)
266{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300267 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000268 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000269 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200270 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300271 int status;
272
273 status = Py_ReprEnter((PyObject *)pto);
274 if (status != 0) {
275 if (status < 0)
276 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000277 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300278 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000279
280 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300281 if (arglist == NULL)
282 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000283 /* Pack positional arguments */
284 assert (PyTuple_Check(pto->args));
285 n = PyTuple_GET_SIZE(pto->args);
286 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300287 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
288 PyTuple_GET_ITEM(pto->args, i)));
289 if (arglist == NULL)
290 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000291 }
292 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200293 assert (PyDict_Check(pto->kw));
294 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Michael Seifert6c3d5272017-03-15 06:26:33 +0100295 /* Prevent key.__str__ from deleting the value. */
296 Py_INCREF(value);
297 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300298 key, value));
Michael Seifert6c3d5272017-03-15 06:26:33 +0100299 Py_DECREF(value);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300300 if (arglist == NULL)
301 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000302 }
303 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
304 pto->fn, arglist);
305 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300306
307 done:
308 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000309 return result;
310}
311
Jack Diederiche0cbd692009-04-01 04:27:09 +0000312/* Pickle strategy:
313 __reduce__ by itself doesn't support getting kwargs in the unpickle
314 operation so we define a __setstate__ that replaces all the information
315 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200316 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000317 */
318
Antoine Pitrou69f71142009-05-24 21:25:49 +0000319static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000320partial_reduce(partialobject *pto, PyObject *unused)
321{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
323 pto->args, pto->kw,
324 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000325}
326
Antoine Pitrou69f71142009-05-24 21:25:49 +0000327static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200328partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000329{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200331
332 if (!PyTuple_Check(state) ||
333 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
334 !PyCallable_Check(fn) ||
335 !PyTuple_Check(fnargs) ||
336 (kw != Py_None && !PyDict_Check(kw)))
337 {
338 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200341
342 if(!PyTuple_CheckExact(fnargs))
343 fnargs = PySequence_Tuple(fnargs);
344 else
345 Py_INCREF(fnargs);
346 if (fnargs == NULL)
347 return NULL;
348
349 if (kw == Py_None)
350 kw = PyDict_New();
351 else if(!PyDict_CheckExact(kw))
352 kw = PyDict_Copy(kw);
353 else
354 Py_INCREF(kw);
355 if (kw == NULL) {
356 Py_DECREF(fnargs);
357 return NULL;
358 }
359
Serhiy Storchaka38741282016-02-02 18:45:17 +0200360 if (dict == Py_None)
361 dict = NULL;
362 else
363 Py_INCREF(dict);
364
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100365 Py_INCREF(fn);
366 pto->use_fastcall = _PyObject_HasFastCall(fn);
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300367 Py_SETREF(pto->fn, fn);
368 Py_SETREF(pto->args, fnargs);
369 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300370 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000372}
373
374static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000375 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200376 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000377 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000378};
379
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000380static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000381 PyVarObject_HEAD_INIT(NULL, 0)
382 "functools.partial", /* tp_name */
383 sizeof(partialobject), /* tp_basicsize */
384 0, /* tp_itemsize */
385 /* methods */
386 (destructor)partial_dealloc, /* tp_dealloc */
387 0, /* tp_print */
388 0, /* tp_getattr */
389 0, /* tp_setattr */
390 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000391 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000392 0, /* tp_as_number */
393 0, /* tp_as_sequence */
394 0, /* tp_as_mapping */
395 0, /* tp_hash */
396 (ternaryfunc)partial_call, /* tp_call */
397 0, /* tp_str */
398 PyObject_GenericGetAttr, /* tp_getattro */
399 PyObject_GenericSetAttr, /* tp_setattro */
400 0, /* tp_as_buffer */
401 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
402 Py_TPFLAGS_BASETYPE, /* tp_flags */
403 partial_doc, /* tp_doc */
404 (traverseproc)partial_traverse, /* tp_traverse */
405 0, /* tp_clear */
406 0, /* tp_richcompare */
407 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
408 0, /* tp_iter */
409 0, /* tp_iternext */
410 partial_methods, /* tp_methods */
411 partial_memberlist, /* tp_members */
412 partial_getsetlist, /* tp_getset */
413 0, /* tp_base */
414 0, /* tp_dict */
415 0, /* tp_descr_get */
416 0, /* tp_descr_set */
417 offsetof(partialobject, dict), /* tp_dictoffset */
418 0, /* tp_init */
419 0, /* tp_alloc */
420 partial_new, /* tp_new */
421 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000422};
423
424
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700425/* cmp_to_key ***************************************************************/
426
427typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200428 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700429 PyObject *cmp;
430 PyObject *object;
431} keyobject;
432
433static void
434keyobject_dealloc(keyobject *ko)
435{
436 Py_DECREF(ko->cmp);
437 Py_XDECREF(ko->object);
438 PyObject_FREE(ko);
439}
440
441static int
442keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
443{
444 Py_VISIT(ko->cmp);
445 if (ko->object)
446 Py_VISIT(ko->object);
447 return 0;
448}
449
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500450static int
451keyobject_clear(keyobject *ko)
452{
453 Py_CLEAR(ko->cmp);
454 if (ko->object)
455 Py_CLEAR(ko->object);
456 return 0;
457}
458
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700459static PyMemberDef keyobject_members[] = {
460 {"obj", T_OBJECT,
461 offsetof(keyobject, object), 0,
462 PyDoc_STR("Value wrapped by a key function.")},
463 {NULL}
464};
465
466static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700467keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700468
469static PyObject *
470keyobject_richcompare(PyObject *ko, PyObject *other, int op);
471
472static PyTypeObject keyobject_type = {
473 PyVarObject_HEAD_INIT(&PyType_Type, 0)
474 "functools.KeyWrapper", /* tp_name */
475 sizeof(keyobject), /* tp_basicsize */
476 0, /* tp_itemsize */
477 /* methods */
478 (destructor)keyobject_dealloc, /* tp_dealloc */
479 0, /* tp_print */
480 0, /* tp_getattr */
481 0, /* tp_setattr */
482 0, /* tp_reserved */
483 0, /* tp_repr */
484 0, /* tp_as_number */
485 0, /* tp_as_sequence */
486 0, /* tp_as_mapping */
487 0, /* tp_hash */
488 (ternaryfunc)keyobject_call, /* tp_call */
489 0, /* tp_str */
490 PyObject_GenericGetAttr, /* tp_getattro */
491 0, /* tp_setattro */
492 0, /* tp_as_buffer */
493 Py_TPFLAGS_DEFAULT, /* tp_flags */
494 0, /* tp_doc */
495 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500496 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700497 keyobject_richcompare, /* tp_richcompare */
498 0, /* tp_weaklistoffset */
499 0, /* tp_iter */
500 0, /* tp_iternext */
501 0, /* tp_methods */
502 keyobject_members, /* tp_members */
503 0, /* tp_getset */
504};
505
506static PyObject *
507keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
508{
509 PyObject *object;
510 keyobject *result;
511 static char *kwargs[] = {"obj", NULL};
512
513 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
514 return NULL;
515 result = PyObject_New(keyobject, &keyobject_type);
516 if (!result)
517 return NULL;
518 Py_INCREF(ko->cmp);
519 result->cmp = ko->cmp;
520 Py_INCREF(object);
521 result->object = object;
522 return (PyObject *)result;
523}
524
525static PyObject *
526keyobject_richcompare(PyObject *ko, PyObject *other, int op)
527{
528 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700529 PyObject *x;
530 PyObject *y;
531 PyObject *compare;
532 PyObject *answer;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200533 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700534
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700535 if (Py_TYPE(other) != &keyobject_type){
536 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
537 return NULL;
538 }
539 compare = ((keyobject *) ko)->cmp;
540 assert(compare != NULL);
541 x = ((keyobject *) ko)->object;
542 y = ((keyobject *) other)->object;
543 if (!x || !y){
544 PyErr_Format(PyExc_AttributeError, "object");
545 return NULL;
546 }
547
548 /* Call the user's comparison function and translate the 3-way
549 * result into true or false (or error).
550 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200551 stack[0] = x;
552 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200553 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200554 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700555 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200556 }
557
Serhiy Storchakaba85d692017-03-30 09:09:41 +0300558 answer = PyObject_RichCompare(res, _PyLong_Zero, op);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700559 Py_DECREF(res);
560 return answer;
561}
562
563static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200564functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
565{
566 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700567 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200568 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700569
570 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
571 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200572 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700573 if (!object)
574 return NULL;
575 Py_INCREF(cmp);
576 object->cmp = cmp;
577 object->object = NULL;
578 return (PyObject *)object;
579}
580
581PyDoc_STRVAR(functools_cmp_to_key_doc,
582"Convert a cmp= function into a key= function.");
583
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000584/* reduce (used to be a builtin) ********************************************/
585
586static PyObject *
587functools_reduce(PyObject *self, PyObject *args)
588{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000589 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000590
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000591 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
592 return NULL;
593 if (result != NULL)
594 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000595
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000596 it = PyObject_GetIter(seq);
597 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000598 if (PyErr_ExceptionMatches(PyExc_TypeError))
599 PyErr_SetString(PyExc_TypeError,
600 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000601 Py_XDECREF(result);
602 return NULL;
603 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000604
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000605 if ((args = PyTuple_New(2)) == NULL)
606 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000607
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000608 for (;;) {
609 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000610
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000611 if (args->ob_refcnt > 1) {
612 Py_DECREF(args);
613 if ((args = PyTuple_New(2)) == NULL)
614 goto Fail;
615 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000616
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000617 op2 = PyIter_Next(it);
618 if (op2 == NULL) {
619 if (PyErr_Occurred())
620 goto Fail;
621 break;
622 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000623
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000624 if (result == NULL)
625 result = op2;
626 else {
627 PyTuple_SetItem(args, 0, result);
628 PyTuple_SetItem(args, 1, op2);
629 if ((result = PyEval_CallObject(func, args)) == NULL)
630 goto Fail;
631 }
632 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000633
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000634 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000635
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000636 if (result == NULL)
637 PyErr_SetString(PyExc_TypeError,
638 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000639
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000640 Py_DECREF(it);
641 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000642
643Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000644 Py_XDECREF(args);
645 Py_XDECREF(result);
646 Py_DECREF(it);
647 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000648}
649
650PyDoc_STRVAR(functools_reduce_doc,
651"reduce(function, sequence[, initial]) -> value\n\
652\n\
653Apply a function of two arguments cumulatively to the items of a sequence,\n\
654from left to right, so as to reduce the sequence to a single value.\n\
655For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
656((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
657of the sequence in the calculation, and serves as a default when the\n\
658sequence is empty.");
659
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300660/* lru_cache object **********************************************************/
661
662/* this object is used delimit args and keywords in the cache keys */
663static PyObject *kwd_mark = NULL;
664
665struct lru_list_elem;
666struct lru_cache_object;
667
668typedef struct lru_list_elem {
669 PyObject_HEAD
670 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300671 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300672 PyObject *key, *result;
673} lru_list_elem;
674
675static void
676lru_list_elem_dealloc(lru_list_elem *link)
677{
678 _PyObject_GC_UNTRACK(link);
679 Py_XDECREF(link->key);
680 Py_XDECREF(link->result);
681 PyObject_GC_Del(link);
682}
683
684static int
685lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
686{
687 Py_VISIT(link->key);
688 Py_VISIT(link->result);
689 return 0;
690}
691
692static int
693lru_list_elem_clear(lru_list_elem *link)
694{
695 Py_CLEAR(link->key);
696 Py_CLEAR(link->result);
697 return 0;
698}
699
700static PyTypeObject lru_list_elem_type = {
701 PyVarObject_HEAD_INIT(&PyType_Type, 0)
702 "functools._lru_list_elem", /* tp_name */
703 sizeof(lru_list_elem), /* tp_basicsize */
704 0, /* tp_itemsize */
705 /* methods */
706 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
707 0, /* tp_print */
708 0, /* tp_getattr */
709 0, /* tp_setattr */
710 0, /* tp_reserved */
711 0, /* tp_repr */
712 0, /* tp_as_number */
713 0, /* tp_as_sequence */
714 0, /* tp_as_mapping */
715 0, /* tp_hash */
716 0, /* tp_call */
717 0, /* tp_str */
718 0, /* tp_getattro */
719 0, /* tp_setattro */
720 0, /* tp_as_buffer */
721 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
722 0, /* tp_doc */
723 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
724 (inquiry)lru_list_elem_clear, /* tp_clear */
725};
726
727
728typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
729
730typedef struct lru_cache_object {
731 lru_list_elem root; /* includes PyObject_HEAD */
732 Py_ssize_t maxsize;
733 PyObject *maxsize_O;
734 PyObject *func;
735 lru_cache_ternaryfunc wrapper;
736 PyObject *cache;
737 PyObject *cache_info_type;
738 Py_ssize_t misses, hits;
739 int typed;
740 PyObject *dict;
741 int full;
742} lru_cache_object;
743
744static PyTypeObject lru_cache_type;
745
746static PyObject *
747lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
748{
Raymond Hettingerdda44682017-01-08 18:04:30 -0800749 PyObject *key, *keyword, *value;
750 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300751
752 /* short path, key will match args anyway, which is a tuple */
753 if (!typed && !kwds) {
754 Py_INCREF(args);
755 return args;
756 }
757
Raymond Hettingerdda44682017-01-08 18:04:30 -0800758 kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
759 assert(kwds_size >= 0);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300760
761 key_size = PyTuple_GET_SIZE(args);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800762 if (kwds_size)
763 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300764 if (typed)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800765 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300766
767 key = PyTuple_New(key_size);
768 if (key == NULL)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800769 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300770
771 key_pos = 0;
772 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
773 PyObject *item = PyTuple_GET_ITEM(args, pos);
774 Py_INCREF(item);
775 PyTuple_SET_ITEM(key, key_pos++, item);
776 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800777 if (kwds_size) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300778 Py_INCREF(kwd_mark);
779 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800780 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
781 Py_INCREF(keyword);
782 PyTuple_SET_ITEM(key, key_pos++, keyword);
783 Py_INCREF(value);
784 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300785 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800786 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300787 }
788 if (typed) {
789 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
790 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
791 Py_INCREF(item);
792 PyTuple_SET_ITEM(key, key_pos++, item);
793 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800794 if (kwds_size) {
795 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
796 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300797 Py_INCREF(item);
798 PyTuple_SET_ITEM(key, key_pos++, item);
799 }
800 }
801 }
802 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300803 return key;
804}
805
806static PyObject *
807uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
808{
809 PyObject *result = PyObject_Call(self->func, args, kwds);
810 if (!result)
811 return NULL;
812 self->misses++;
813 return result;
814}
815
816static PyObject *
817infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
818{
819 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300820 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300821 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
822 if (!key)
823 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300824 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500825 if (hash == -1) {
826 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300827 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500828 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300829 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300830 if (result) {
831 Py_INCREF(result);
832 self->hits++;
833 Py_DECREF(key);
834 return result;
835 }
836 if (PyErr_Occurred()) {
837 Py_DECREF(key);
838 return NULL;
839 }
840 result = PyObject_Call(self->func, args, kwds);
841 if (!result) {
842 Py_DECREF(key);
843 return NULL;
844 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300845 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300846 Py_DECREF(result);
847 Py_DECREF(key);
848 return NULL;
849 }
850 Py_DECREF(key);
851 self->misses++;
852 return result;
853}
854
855static void
856lru_cache_extricate_link(lru_list_elem *link)
857{
858 link->prev->next = link->next;
859 link->next->prev = link->prev;
860}
861
862static void
863lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
864{
865 lru_list_elem *root = &self->root;
866 lru_list_elem *last = root->prev;
867 last->next = root->prev = link;
868 link->prev = last;
869 link->next = root;
870}
871
872static PyObject *
873bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
874{
875 lru_list_elem *link;
876 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300877 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300878
879 key = lru_cache_make_key(args, kwds, self->typed);
880 if (!key)
881 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300882 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500883 if (hash == -1) {
884 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300885 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500886 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300887 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300888 if (link) {
889 lru_cache_extricate_link(link);
890 lru_cache_append_link(self, link);
891 self->hits++;
892 result = link->result;
893 Py_INCREF(result);
894 Py_DECREF(key);
895 return result;
896 }
897 if (PyErr_Occurred()) {
898 Py_DECREF(key);
899 return NULL;
900 }
901 result = PyObject_Call(self->func, args, kwds);
902 if (!result) {
903 Py_DECREF(key);
904 return NULL;
905 }
906 if (self->full && self->root.next != &self->root) {
907 /* Use the oldest item to store the new key and result. */
Serhiy Storchaka67796522017-01-12 18:34:33 +0200908 PyObject *oldkey, *oldresult, *popresult;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300909 /* Extricate the oldest item. */
910 link = self->root.next;
911 lru_cache_extricate_link(link);
912 /* Remove it from the cache.
913 The cache dict holds one reference to the link,
914 and the linked list holds yet one reference to it. */
Serhiy Storchaka42e1ea92017-01-12 19:12:21 +0200915 popresult = _PyDict_Pop_KnownHash(self->cache,
Serhiy Storchaka67796522017-01-12 18:34:33 +0200916 link->key, link->hash,
917 Py_None);
918 if (popresult == Py_None) {
919 /* Getting here means that this same key was added to the
920 cache while the lock was released. Since the link
921 update is already done, we need only return the
922 computed result and update the count of misses. */
923 Py_DECREF(popresult);
924 Py_DECREF(link);
925 Py_DECREF(key);
926 }
927 else if (popresult == NULL) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300928 lru_cache_append_link(self, link);
929 Py_DECREF(key);
930 Py_DECREF(result);
931 return NULL;
932 }
Serhiy Storchaka67796522017-01-12 18:34:33 +0200933 else {
934 Py_DECREF(popresult);
935 /* Keep a reference to the old key and old result to
936 prevent their ref counts from going to zero during the
937 update. That will prevent potentially arbitrary object
938 clean-up code (i.e. __del__) from running while we're
939 still adjusting the links. */
940 oldkey = link->key;
941 oldresult = link->result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300942
Serhiy Storchaka67796522017-01-12 18:34:33 +0200943 link->hash = hash;
944 link->key = key;
945 link->result = result;
946 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
947 hash) < 0) {
948 Py_DECREF(link);
949 Py_DECREF(oldkey);
950 Py_DECREF(oldresult);
951 return NULL;
952 }
953 lru_cache_append_link(self, link);
954 Py_INCREF(result); /* for return */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300955 Py_DECREF(oldkey);
956 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300957 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300958 } else {
959 /* Put result in a new link at the front of the queue. */
960 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
961 &lru_list_elem_type);
962 if (link == NULL) {
963 Py_DECREF(key);
964 Py_DECREF(result);
965 return NULL;
966 }
967
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300968 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300969 link->key = key;
970 link->result = result;
971 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300972 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
973 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300974 Py_DECREF(link);
975 return NULL;
976 }
977 lru_cache_append_link(self, link);
978 Py_INCREF(result); /* for return */
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200979 self->full = (PyDict_GET_SIZE(self->cache) >= self->maxsize);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300980 }
981 self->misses++;
982 return result;
983}
984
985static PyObject *
986lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
987{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300988 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300989 int typed;
990 lru_cache_object *obj;
991 Py_ssize_t maxsize;
992 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
993 static char *keywords[] = {"user_function", "maxsize", "typed",
994 "cache_info_type", NULL};
995
996 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
997 &func, &maxsize_O, &typed,
998 &cache_info_type)) {
999 return NULL;
1000 }
1001
1002 if (!PyCallable_Check(func)) {
1003 PyErr_SetString(PyExc_TypeError,
1004 "the first argument must be callable");
1005 return NULL;
1006 }
1007
1008 /* select the caching function, and make/inc maxsize_O */
1009 if (maxsize_O == Py_None) {
1010 wrapper = infinite_lru_cache_wrapper;
1011 /* use this only to initialize lru_cache_object attribute maxsize */
1012 maxsize = -1;
1013 } else if (PyIndex_Check(maxsize_O)) {
1014 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1015 if (maxsize == -1 && PyErr_Occurred())
1016 return NULL;
1017 if (maxsize == 0)
1018 wrapper = uncached_lru_cache_wrapper;
1019 else
1020 wrapper = bounded_lru_cache_wrapper;
1021 } else {
1022 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1023 return NULL;
1024 }
1025
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001026 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001027 return NULL;
1028
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001029 obj = (lru_cache_object *)type->tp_alloc(type, 0);
1030 if (obj == NULL) {
1031 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001032 return NULL;
1033 }
1034
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001035 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001036 obj->root.prev = &obj->root;
1037 obj->root.next = &obj->root;
1038 obj->maxsize = maxsize;
1039 Py_INCREF(maxsize_O);
1040 obj->maxsize_O = maxsize_O;
1041 Py_INCREF(func);
1042 obj->func = func;
1043 obj->wrapper = wrapper;
1044 obj->misses = obj->hits = 0;
1045 obj->typed = typed;
1046 Py_INCREF(cache_info_type);
1047 obj->cache_info_type = cache_info_type;
1048
1049 return (PyObject *)obj;
1050}
1051
1052static lru_list_elem *
1053lru_cache_unlink_list(lru_cache_object *self)
1054{
1055 lru_list_elem *root = &self->root;
1056 lru_list_elem *link = root->next;
1057 if (link == root)
1058 return NULL;
1059 root->prev->next = NULL;
1060 root->next = root->prev = root;
1061 return link;
1062}
1063
1064static void
1065lru_cache_clear_list(lru_list_elem *link)
1066{
1067 while (link != NULL) {
1068 lru_list_elem *next = link->next;
1069 Py_DECREF(link);
1070 link = next;
1071 }
1072}
1073
1074static void
1075lru_cache_dealloc(lru_cache_object *obj)
1076{
INADA Naokia6296d32017-08-24 14:55:17 +09001077 lru_list_elem *list;
1078 /* bpo-31095: UnTrack is needed before calling any callbacks */
1079 PyObject_GC_UnTrack(obj);
1080
1081 list = lru_cache_unlink_list(obj);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001082 Py_XDECREF(obj->maxsize_O);
1083 Py_XDECREF(obj->func);
1084 Py_XDECREF(obj->cache);
1085 Py_XDECREF(obj->dict);
1086 Py_XDECREF(obj->cache_info_type);
1087 lru_cache_clear_list(list);
1088 Py_TYPE(obj)->tp_free(obj);
1089}
1090
1091static PyObject *
1092lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1093{
1094 return self->wrapper(self, args, kwds);
1095}
1096
1097static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001098lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1099{
1100 if (obj == Py_None || obj == NULL) {
1101 Py_INCREF(self);
1102 return self;
1103 }
1104 return PyMethod_New(self, obj);
1105}
1106
1107static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001108lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1109{
1110 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1111 self->hits, self->misses, self->maxsize_O,
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +02001112 PyDict_GET_SIZE(self->cache));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001113}
1114
1115static PyObject *
1116lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1117{
1118 lru_list_elem *list = lru_cache_unlink_list(self);
1119 self->hits = self->misses = 0;
1120 self->full = 0;
1121 PyDict_Clear(self->cache);
1122 lru_cache_clear_list(list);
1123 Py_RETURN_NONE;
1124}
1125
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001126static PyObject *
1127lru_cache_reduce(PyObject *self, PyObject *unused)
1128{
1129 return PyObject_GetAttrString(self, "__qualname__");
1130}
1131
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001132static PyObject *
1133lru_cache_copy(PyObject *self, PyObject *unused)
1134{
1135 Py_INCREF(self);
1136 return self;
1137}
1138
1139static PyObject *
1140lru_cache_deepcopy(PyObject *self, PyObject *unused)
1141{
1142 Py_INCREF(self);
1143 return self;
1144}
1145
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001146static int
1147lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1148{
1149 lru_list_elem *link = self->root.next;
1150 while (link != &self->root) {
1151 lru_list_elem *next = link->next;
1152 Py_VISIT(link);
1153 link = next;
1154 }
1155 Py_VISIT(self->maxsize_O);
1156 Py_VISIT(self->func);
1157 Py_VISIT(self->cache);
1158 Py_VISIT(self->cache_info_type);
1159 Py_VISIT(self->dict);
1160 return 0;
1161}
1162
1163static int
1164lru_cache_tp_clear(lru_cache_object *self)
1165{
1166 lru_list_elem *list = lru_cache_unlink_list(self);
1167 Py_CLEAR(self->maxsize_O);
1168 Py_CLEAR(self->func);
1169 Py_CLEAR(self->cache);
1170 Py_CLEAR(self->cache_info_type);
1171 Py_CLEAR(self->dict);
1172 lru_cache_clear_list(list);
1173 return 0;
1174}
1175
1176
1177PyDoc_STRVAR(lru_cache_doc,
1178"Create a cached callable that wraps another function.\n\
1179\n\
1180user_function: the function being cached\n\
1181\n\
1182maxsize: 0 for no caching\n\
1183 None for unlimited cache size\n\
1184 n for a bounded cache\n\
1185\n\
1186typed: False cache f(3) and f(3.0) as identical calls\n\
1187 True cache f(3) and f(3.0) as distinct calls\n\
1188\n\
1189cache_info_type: namedtuple class with the fields:\n\
1190 hits misses currsize maxsize\n"
1191);
1192
1193static PyMethodDef lru_cache_methods[] = {
1194 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1195 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001196 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001197 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1198 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001199 {NULL}
1200};
1201
1202static PyGetSetDef lru_cache_getsetlist[] = {
1203 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1204 {NULL}
1205};
1206
1207static PyTypeObject lru_cache_type = {
1208 PyVarObject_HEAD_INIT(NULL, 0)
1209 "functools._lru_cache_wrapper", /* tp_name */
1210 sizeof(lru_cache_object), /* tp_basicsize */
1211 0, /* tp_itemsize */
1212 /* methods */
1213 (destructor)lru_cache_dealloc, /* tp_dealloc */
1214 0, /* tp_print */
1215 0, /* tp_getattr */
1216 0, /* tp_setattr */
1217 0, /* tp_reserved */
1218 0, /* tp_repr */
1219 0, /* tp_as_number */
1220 0, /* tp_as_sequence */
1221 0, /* tp_as_mapping */
1222 0, /* tp_hash */
1223 (ternaryfunc)lru_cache_call, /* tp_call */
1224 0, /* tp_str */
1225 0, /* tp_getattro */
1226 0, /* tp_setattro */
1227 0, /* tp_as_buffer */
1228 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1229 /* tp_flags */
1230 lru_cache_doc, /* tp_doc */
1231 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1232 (inquiry)lru_cache_tp_clear, /* tp_clear */
1233 0, /* tp_richcompare */
1234 0, /* tp_weaklistoffset */
1235 0, /* tp_iter */
1236 0, /* tp_iternext */
1237 lru_cache_methods, /* tp_methods */
1238 0, /* tp_members */
1239 lru_cache_getsetlist, /* tp_getset */
1240 0, /* tp_base */
1241 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001242 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001243 0, /* tp_descr_set */
1244 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1245 0, /* tp_init */
1246 0, /* tp_alloc */
1247 lru_cache_new, /* tp_new */
1248};
1249
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001250/* module level code ********************************************************/
1251
1252PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001253"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001254
1255static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001256 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001257 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1258 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001259 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001260};
1261
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001262static void
1263module_free(void *m)
1264{
1265 Py_CLEAR(kwd_mark);
1266}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001267
1268static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001269 PyModuleDef_HEAD_INIT,
1270 "_functools",
1271 module_doc,
1272 -1,
1273 module_methods,
1274 NULL,
1275 NULL,
1276 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001277 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001278};
1279
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001280PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001281PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001282{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001283 int i;
1284 PyObject *m;
1285 char *name;
1286 PyTypeObject *typelist[] = {
1287 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001288 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001289 NULL
1290 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001291
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001292 m = PyModule_Create(&_functoolsmodule);
1293 if (m == NULL)
1294 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001295
Victor Stinnera5ed5f02016-12-06 18:45:50 +01001296 kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001297 if (!kwd_mark) {
1298 Py_DECREF(m);
1299 return NULL;
1300 }
1301
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001302 for (i=0 ; typelist[i] != NULL ; i++) {
1303 if (PyType_Ready(typelist[i]) < 0) {
1304 Py_DECREF(m);
1305 return NULL;
1306 }
1307 name = strchr(typelist[i]->tp_name, '.');
1308 assert (name != NULL);
1309 Py_INCREF(typelist[i]);
1310 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1311 }
1312 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001313}