blob: a571045bcc75f59b7322487da2d613d13f1dadeb [file] [log] [blame]
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001
2#include "Python.h"
Eric Snow2ebc5ce2017-09-07 23:51:28 -06003#include "internal/mem.h"
4#include "internal/pystate.h"
Raymond Hettinger9c323f82005-02-28 19:39:44 +00005#include "structmember.h"
6
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00007/* _functools module written and maintained
Raymond Hettinger9c323f82005-02-28 19:39:44 +00008 by Hye-Shik Chang <perky@FreeBSD.org>
9 with adaptations by Raymond Hettinger <python@rcn.com>
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000010 Copyright (c) 2004, 2005, 2006 Python Software Foundation.
Raymond Hettinger9c323f82005-02-28 19:39:44 +000011 All rights reserved.
12*/
13
14/* partial object **********************************************************/
15
16typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000017 PyObject_HEAD
18 PyObject *fn;
19 PyObject *args;
20 PyObject *kw;
21 PyObject *dict;
22 PyObject *weakreflist; /* List of weak references */
Victor Stinner0f7b0b32017-03-14 21:37:20 +010023 int use_fastcall;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000024} partialobject;
25
26static PyTypeObject partial_type;
27
28static PyObject *
29partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
30{
Alexander Belopolskye49af342015-03-01 15:08:17 -050031 PyObject *func, *pargs, *nargs, *pkw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000032 partialobject *pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000033
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000034 if (PyTuple_GET_SIZE(args) < 1) {
35 PyErr_SetString(PyExc_TypeError,
36 "type 'partial' takes at least one argument");
37 return NULL;
38 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000039
Serhiy Storchaka38741282016-02-02 18:45:17 +020040 pargs = pkw = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000041 func = PyTuple_GET_ITEM(args, 0);
Alexander Belopolskye49af342015-03-01 15:08:17 -050042 if (Py_TYPE(func) == &partial_type && type == &partial_type) {
43 partialobject *part = (partialobject *)func;
44 if (part->dict == NULL) {
45 pargs = part->args;
46 pkw = part->kw;
47 func = part->fn;
Serhiy Storchaka38741282016-02-02 18:45:17 +020048 assert(PyTuple_Check(pargs));
49 assert(PyDict_Check(pkw));
Alexander Belopolskye49af342015-03-01 15:08:17 -050050 }
51 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000052 if (!PyCallable_Check(func)) {
53 PyErr_SetString(PyExc_TypeError,
54 "the first argument must be callable");
55 return NULL;
56 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000057
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000058 /* create partialobject structure */
59 pto = (partialobject *)type->tp_alloc(type, 0);
60 if (pto == NULL)
61 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000062
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000063 pto->fn = func;
64 Py_INCREF(func);
Alexander Belopolskye49af342015-03-01 15:08:17 -050065
66 nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
67 if (nargs == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000068 Py_DECREF(pto);
69 return NULL;
70 }
Serhiy Storchaka3c749fc2017-03-25 12:10:16 +020071 if (pargs == NULL) {
Alexander Belopolskye49af342015-03-01 15:08:17 -050072 pto->args = nargs;
Alexander Belopolskye49af342015-03-01 15:08:17 -050073 }
74 else {
75 pto->args = PySequence_Concat(pargs, nargs);
Serhiy Storchaka3c749fc2017-03-25 12:10:16 +020076 Py_DECREF(nargs);
Alexander Belopolskye49af342015-03-01 15:08:17 -050077 if (pto->args == NULL) {
Alexander Belopolskye49af342015-03-01 15:08:17 -050078 Py_DECREF(pto);
79 return NULL;
80 }
Serhiy Storchaka38741282016-02-02 18:45:17 +020081 assert(PyTuple_Check(pto->args));
Alexander Belopolskye49af342015-03-01 15:08:17 -050082 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050083
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +020084 if (pkw == NULL || PyDict_GET_SIZE(pkw) == 0) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020085 if (kw == NULL) {
86 pto->kw = PyDict_New();
Alexander Belopolskye49af342015-03-01 15:08:17 -050087 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +020088 else if (Py_REFCNT(kw) == 1) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020089 Py_INCREF(kw);
90 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000091 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +020092 else {
93 pto->kw = PyDict_Copy(kw);
94 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050095 }
96 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +020097 pto->kw = PyDict_Copy(pkw);
98 if (kw != NULL && pto->kw != NULL) {
99 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -0400100 Py_DECREF(pto);
101 return NULL;
102 }
103 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200105 if (pto->kw == NULL) {
106 Py_DECREF(pto);
107 return NULL;
108 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000109
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100110 pto->use_fastcall = _PyObject_HasFastCall(func);
111
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000112 return (PyObject *)pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000113}
114
115static void
116partial_dealloc(partialobject *pto)
117{
INADA Naokia6296d32017-08-24 14:55:17 +0900118 /* bpo-31095: UnTrack is needed before calling any callbacks */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000119 PyObject_GC_UnTrack(pto);
120 if (pto->weakreflist != NULL)
121 PyObject_ClearWeakRefs((PyObject *) pto);
122 Py_XDECREF(pto->fn);
123 Py_XDECREF(pto->args);
124 Py_XDECREF(pto->kw);
125 Py_XDECREF(pto->dict);
126 Py_TYPE(pto)->tp_free(pto);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000127}
128
129static PyObject *
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100130partial_fastcall(partialobject *pto, PyObject **args, Py_ssize_t nargs,
131 PyObject *kwargs)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000132{
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100133 PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000134 PyObject *ret;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100135 PyObject **stack, **stack_buf = NULL;
136 Py_ssize_t nargs2, pto_nargs;
137
138 pto_nargs = PyTuple_GET_SIZE(pto->args);
139 nargs2 = pto_nargs + nargs;
140
141 if (pto_nargs == 0) {
142 stack = args;
143 }
144 else if (nargs == 0) {
145 stack = &PyTuple_GET_ITEM(pto->args, 0);
146 }
147 else {
148 if (nargs2 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
149 stack = small_stack;
150 }
151 else {
152 stack_buf = PyMem_Malloc(nargs2 * sizeof(PyObject *));
153 if (stack_buf == NULL) {
154 PyErr_NoMemory();
155 return NULL;
156 }
157 stack = stack_buf;
158 }
159
160 /* use borrowed references */
161 memcpy(stack,
162 &PyTuple_GET_ITEM(pto->args, 0),
163 pto_nargs * sizeof(PyObject*));
164 memcpy(&stack[pto_nargs],
165 args,
166 nargs * sizeof(PyObject*));
167 }
168
169 ret = _PyObject_FastCallDict(pto->fn, stack, nargs2, kwargs);
170 PyMem_Free(stack_buf);
171 return ret;
172}
173
174static PyObject *
175partial_call_impl(partialobject *pto, PyObject *args, PyObject *kwargs)
176{
177 PyObject *ret, *args2;
178
179 /* Note: tupleconcat() is optimized for empty tuples */
180 args2 = PySequence_Concat(pto->args, args);
181 if (args2 == NULL) {
182 return NULL;
183 }
184 assert(PyTuple_Check(args2));
185
186 ret = PyObject_Call(pto->fn, args2, kwargs);
187 Py_DECREF(args2);
188 return ret;
189}
190
191static PyObject *
192partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
193{
194 PyObject *kwargs2, *res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000195
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000196 assert (PyCallable_Check(pto->fn));
197 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200198 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000199
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200200 if (PyDict_GET_SIZE(pto->kw) == 0) {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100201 /* kwargs can be NULL */
202 kwargs2 = kwargs;
203 Py_XINCREF(kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200204 }
205 else {
Victor Stinner561ca802017-02-23 18:26:43 +0100206 /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
207 copied, because a function using "**kwargs" can modify the
208 dictionary. */
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100209 kwargs2 = PyDict_Copy(pto->kw);
210 if (kwargs2 == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000211 return NULL;
212 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200213
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100214 if (kwargs != NULL) {
215 if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
216 Py_DECREF(kwargs2);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 return NULL;
218 }
219 }
220 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000221
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100222
223 if (pto->use_fastcall) {
224 res = partial_fastcall(pto,
225 &PyTuple_GET_ITEM(args, 0),
226 PyTuple_GET_SIZE(args),
227 kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200228 }
229 else {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100230 res = partial_call_impl(pto, args, kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200231 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100232 Py_XDECREF(kwargs2);
233 return res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000234}
235
236static int
237partial_traverse(partialobject *pto, visitproc visit, void *arg)
238{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000239 Py_VISIT(pto->fn);
240 Py_VISIT(pto->args);
241 Py_VISIT(pto->kw);
242 Py_VISIT(pto->dict);
243 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000244}
245
246PyDoc_STRVAR(partial_doc,
247"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000248 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000249
250#define OFF(x) offsetof(partialobject, x)
251static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 {"func", T_OBJECT, OFF(fn), READONLY,
253 "function object to use in future partial calls"},
254 {"args", T_OBJECT, OFF(args), READONLY,
255 "tuple of arguments to future partial calls"},
256 {"keywords", T_OBJECT, OFF(kw), READONLY,
257 "dictionary of keyword arguments to future partial calls"},
258 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000259};
260
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000261static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500262 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000264};
265
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000266static PyObject *
267partial_repr(partialobject *pto)
268{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300269 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000270 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000271 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200272 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300273 int status;
274
275 status = Py_ReprEnter((PyObject *)pto);
276 if (status != 0) {
277 if (status < 0)
278 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000279 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300280 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000281
282 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300283 if (arglist == NULL)
284 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000285 /* Pack positional arguments */
286 assert (PyTuple_Check(pto->args));
287 n = PyTuple_GET_SIZE(pto->args);
288 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300289 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
290 PyTuple_GET_ITEM(pto->args, i)));
291 if (arglist == NULL)
292 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000293 }
294 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200295 assert (PyDict_Check(pto->kw));
296 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Michael Seifert6c3d5272017-03-15 06:26:33 +0100297 /* Prevent key.__str__ from deleting the value. */
298 Py_INCREF(value);
299 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300300 key, value));
Michael Seifert6c3d5272017-03-15 06:26:33 +0100301 Py_DECREF(value);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300302 if (arglist == NULL)
303 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000304 }
305 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
306 pto->fn, arglist);
307 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300308
309 done:
310 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000311 return result;
312}
313
Jack Diederiche0cbd692009-04-01 04:27:09 +0000314/* Pickle strategy:
315 __reduce__ by itself doesn't support getting kwargs in the unpickle
316 operation so we define a __setstate__ that replaces all the information
317 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200318 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000319 */
320
Antoine Pitrou69f71142009-05-24 21:25:49 +0000321static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000322partial_reduce(partialobject *pto, PyObject *unused)
323{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000324 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
325 pto->args, pto->kw,
326 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000327}
328
Antoine Pitrou69f71142009-05-24 21:25:49 +0000329static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200330partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000331{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200333
334 if (!PyTuple_Check(state) ||
335 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
336 !PyCallable_Check(fn) ||
337 !PyTuple_Check(fnargs) ||
338 (kw != Py_None && !PyDict_Check(kw)))
339 {
340 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000342 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200343
344 if(!PyTuple_CheckExact(fnargs))
345 fnargs = PySequence_Tuple(fnargs);
346 else
347 Py_INCREF(fnargs);
348 if (fnargs == NULL)
349 return NULL;
350
351 if (kw == Py_None)
352 kw = PyDict_New();
353 else if(!PyDict_CheckExact(kw))
354 kw = PyDict_Copy(kw);
355 else
356 Py_INCREF(kw);
357 if (kw == NULL) {
358 Py_DECREF(fnargs);
359 return NULL;
360 }
361
Serhiy Storchaka38741282016-02-02 18:45:17 +0200362 if (dict == Py_None)
363 dict = NULL;
364 else
365 Py_INCREF(dict);
366
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100367 Py_INCREF(fn);
368 pto->use_fastcall = _PyObject_HasFastCall(fn);
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300369 Py_SETREF(pto->fn, fn);
370 Py_SETREF(pto->args, fnargs);
371 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300372 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000373 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000374}
375
376static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000377 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200378 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000379 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000380};
381
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000382static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000383 PyVarObject_HEAD_INIT(NULL, 0)
384 "functools.partial", /* tp_name */
385 sizeof(partialobject), /* tp_basicsize */
386 0, /* tp_itemsize */
387 /* methods */
388 (destructor)partial_dealloc, /* tp_dealloc */
389 0, /* tp_print */
390 0, /* tp_getattr */
391 0, /* tp_setattr */
392 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000393 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 0, /* tp_as_number */
395 0, /* tp_as_sequence */
396 0, /* tp_as_mapping */
397 0, /* tp_hash */
398 (ternaryfunc)partial_call, /* tp_call */
399 0, /* tp_str */
400 PyObject_GenericGetAttr, /* tp_getattro */
401 PyObject_GenericSetAttr, /* tp_setattro */
402 0, /* tp_as_buffer */
403 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
404 Py_TPFLAGS_BASETYPE, /* tp_flags */
405 partial_doc, /* tp_doc */
406 (traverseproc)partial_traverse, /* tp_traverse */
407 0, /* tp_clear */
408 0, /* tp_richcompare */
409 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
410 0, /* tp_iter */
411 0, /* tp_iternext */
412 partial_methods, /* tp_methods */
413 partial_memberlist, /* tp_members */
414 partial_getsetlist, /* tp_getset */
415 0, /* tp_base */
416 0, /* tp_dict */
417 0, /* tp_descr_get */
418 0, /* tp_descr_set */
419 offsetof(partialobject, dict), /* tp_dictoffset */
420 0, /* tp_init */
421 0, /* tp_alloc */
422 partial_new, /* tp_new */
423 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000424};
425
426
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700427/* cmp_to_key ***************************************************************/
428
429typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200430 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700431 PyObject *cmp;
432 PyObject *object;
433} keyobject;
434
435static void
436keyobject_dealloc(keyobject *ko)
437{
438 Py_DECREF(ko->cmp);
439 Py_XDECREF(ko->object);
440 PyObject_FREE(ko);
441}
442
443static int
444keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
445{
446 Py_VISIT(ko->cmp);
447 if (ko->object)
448 Py_VISIT(ko->object);
449 return 0;
450}
451
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500452static int
453keyobject_clear(keyobject *ko)
454{
455 Py_CLEAR(ko->cmp);
456 if (ko->object)
457 Py_CLEAR(ko->object);
458 return 0;
459}
460
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700461static PyMemberDef keyobject_members[] = {
462 {"obj", T_OBJECT,
463 offsetof(keyobject, object), 0,
464 PyDoc_STR("Value wrapped by a key function.")},
465 {NULL}
466};
467
468static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700469keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700470
471static PyObject *
472keyobject_richcompare(PyObject *ko, PyObject *other, int op);
473
474static PyTypeObject keyobject_type = {
475 PyVarObject_HEAD_INIT(&PyType_Type, 0)
476 "functools.KeyWrapper", /* tp_name */
477 sizeof(keyobject), /* tp_basicsize */
478 0, /* tp_itemsize */
479 /* methods */
480 (destructor)keyobject_dealloc, /* tp_dealloc */
481 0, /* tp_print */
482 0, /* tp_getattr */
483 0, /* tp_setattr */
484 0, /* tp_reserved */
485 0, /* tp_repr */
486 0, /* tp_as_number */
487 0, /* tp_as_sequence */
488 0, /* tp_as_mapping */
489 0, /* tp_hash */
490 (ternaryfunc)keyobject_call, /* tp_call */
491 0, /* tp_str */
492 PyObject_GenericGetAttr, /* tp_getattro */
493 0, /* tp_setattro */
494 0, /* tp_as_buffer */
495 Py_TPFLAGS_DEFAULT, /* tp_flags */
496 0, /* tp_doc */
497 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500498 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700499 keyobject_richcompare, /* tp_richcompare */
500 0, /* tp_weaklistoffset */
501 0, /* tp_iter */
502 0, /* tp_iternext */
503 0, /* tp_methods */
504 keyobject_members, /* tp_members */
505 0, /* tp_getset */
506};
507
508static PyObject *
509keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
510{
511 PyObject *object;
512 keyobject *result;
513 static char *kwargs[] = {"obj", NULL};
514
515 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
516 return NULL;
517 result = PyObject_New(keyobject, &keyobject_type);
518 if (!result)
519 return NULL;
520 Py_INCREF(ko->cmp);
521 result->cmp = ko->cmp;
522 Py_INCREF(object);
523 result->object = object;
524 return (PyObject *)result;
525}
526
527static PyObject *
528keyobject_richcompare(PyObject *ko, PyObject *other, int op)
529{
530 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700531 PyObject *x;
532 PyObject *y;
533 PyObject *compare;
534 PyObject *answer;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200535 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700536
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700537 if (Py_TYPE(other) != &keyobject_type){
538 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
539 return NULL;
540 }
541 compare = ((keyobject *) ko)->cmp;
542 assert(compare != NULL);
543 x = ((keyobject *) ko)->object;
544 y = ((keyobject *) other)->object;
545 if (!x || !y){
546 PyErr_Format(PyExc_AttributeError, "object");
547 return NULL;
548 }
549
550 /* Call the user's comparison function and translate the 3-way
551 * result into true or false (or error).
552 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200553 stack[0] = x;
554 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200555 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200556 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700557 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200558 }
559
Serhiy Storchakaba85d692017-03-30 09:09:41 +0300560 answer = PyObject_RichCompare(res, _PyLong_Zero, op);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700561 Py_DECREF(res);
562 return answer;
563}
564
565static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200566functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
567{
568 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700569 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200570 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700571
572 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
573 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200574 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700575 if (!object)
576 return NULL;
577 Py_INCREF(cmp);
578 object->cmp = cmp;
579 object->object = NULL;
580 return (PyObject *)object;
581}
582
583PyDoc_STRVAR(functools_cmp_to_key_doc,
584"Convert a cmp= function into a key= function.");
585
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000586/* reduce (used to be a builtin) ********************************************/
587
588static PyObject *
589functools_reduce(PyObject *self, PyObject *args)
590{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000591 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000592
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000593 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
594 return NULL;
595 if (result != NULL)
596 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000597
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000598 it = PyObject_GetIter(seq);
599 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000600 if (PyErr_ExceptionMatches(PyExc_TypeError))
601 PyErr_SetString(PyExc_TypeError,
602 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000603 Py_XDECREF(result);
604 return NULL;
605 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000606
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000607 if ((args = PyTuple_New(2)) == NULL)
608 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000609
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000610 for (;;) {
611 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000612
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000613 if (args->ob_refcnt > 1) {
614 Py_DECREF(args);
615 if ((args = PyTuple_New(2)) == NULL)
616 goto Fail;
617 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000618
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000619 op2 = PyIter_Next(it);
620 if (op2 == NULL) {
621 if (PyErr_Occurred())
622 goto Fail;
623 break;
624 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000625
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000626 if (result == NULL)
627 result = op2;
628 else {
629 PyTuple_SetItem(args, 0, result);
630 PyTuple_SetItem(args, 1, op2);
631 if ((result = PyEval_CallObject(func, args)) == NULL)
632 goto Fail;
633 }
634 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000635
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000636 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000637
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000638 if (result == NULL)
639 PyErr_SetString(PyExc_TypeError,
640 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000641
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000642 Py_DECREF(it);
643 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000644
645Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000646 Py_XDECREF(args);
647 Py_XDECREF(result);
648 Py_DECREF(it);
649 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000650}
651
652PyDoc_STRVAR(functools_reduce_doc,
653"reduce(function, sequence[, initial]) -> value\n\
654\n\
655Apply a function of two arguments cumulatively to the items of a sequence,\n\
656from left to right, so as to reduce the sequence to a single value.\n\
657For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
658((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
659of the sequence in the calculation, and serves as a default when the\n\
660sequence is empty.");
661
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300662/* lru_cache object **********************************************************/
663
664/* this object is used delimit args and keywords in the cache keys */
665static PyObject *kwd_mark = NULL;
666
667struct lru_list_elem;
668struct lru_cache_object;
669
670typedef struct lru_list_elem {
671 PyObject_HEAD
672 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300673 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300674 PyObject *key, *result;
675} lru_list_elem;
676
677static void
678lru_list_elem_dealloc(lru_list_elem *link)
679{
680 _PyObject_GC_UNTRACK(link);
681 Py_XDECREF(link->key);
682 Py_XDECREF(link->result);
683 PyObject_GC_Del(link);
684}
685
686static int
687lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
688{
689 Py_VISIT(link->key);
690 Py_VISIT(link->result);
691 return 0;
692}
693
694static int
695lru_list_elem_clear(lru_list_elem *link)
696{
697 Py_CLEAR(link->key);
698 Py_CLEAR(link->result);
699 return 0;
700}
701
702static PyTypeObject lru_list_elem_type = {
703 PyVarObject_HEAD_INIT(&PyType_Type, 0)
704 "functools._lru_list_elem", /* tp_name */
705 sizeof(lru_list_elem), /* tp_basicsize */
706 0, /* tp_itemsize */
707 /* methods */
708 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
709 0, /* tp_print */
710 0, /* tp_getattr */
711 0, /* tp_setattr */
712 0, /* tp_reserved */
713 0, /* tp_repr */
714 0, /* tp_as_number */
715 0, /* tp_as_sequence */
716 0, /* tp_as_mapping */
717 0, /* tp_hash */
718 0, /* tp_call */
719 0, /* tp_str */
720 0, /* tp_getattro */
721 0, /* tp_setattro */
722 0, /* tp_as_buffer */
723 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
724 0, /* tp_doc */
725 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
726 (inquiry)lru_list_elem_clear, /* tp_clear */
727};
728
729
730typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
731
732typedef struct lru_cache_object {
733 lru_list_elem root; /* includes PyObject_HEAD */
734 Py_ssize_t maxsize;
735 PyObject *maxsize_O;
736 PyObject *func;
737 lru_cache_ternaryfunc wrapper;
738 PyObject *cache;
739 PyObject *cache_info_type;
740 Py_ssize_t misses, hits;
741 int typed;
742 PyObject *dict;
743 int full;
744} lru_cache_object;
745
746static PyTypeObject lru_cache_type;
747
748static PyObject *
749lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
750{
Raymond Hettingerdda44682017-01-08 18:04:30 -0800751 PyObject *key, *keyword, *value;
752 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300753
754 /* short path, key will match args anyway, which is a tuple */
755 if (!typed && !kwds) {
756 Py_INCREF(args);
757 return args;
758 }
759
Raymond Hettingerdda44682017-01-08 18:04:30 -0800760 kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
761 assert(kwds_size >= 0);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300762
763 key_size = PyTuple_GET_SIZE(args);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800764 if (kwds_size)
765 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300766 if (typed)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800767 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300768
769 key = PyTuple_New(key_size);
770 if (key == NULL)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800771 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300772
773 key_pos = 0;
774 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
775 PyObject *item = PyTuple_GET_ITEM(args, pos);
776 Py_INCREF(item);
777 PyTuple_SET_ITEM(key, key_pos++, item);
778 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800779 if (kwds_size) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300780 Py_INCREF(kwd_mark);
781 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800782 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
783 Py_INCREF(keyword);
784 PyTuple_SET_ITEM(key, key_pos++, keyword);
785 Py_INCREF(value);
786 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300787 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800788 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300789 }
790 if (typed) {
791 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
792 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
793 Py_INCREF(item);
794 PyTuple_SET_ITEM(key, key_pos++, item);
795 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800796 if (kwds_size) {
797 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
798 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300799 Py_INCREF(item);
800 PyTuple_SET_ITEM(key, key_pos++, item);
801 }
802 }
803 }
804 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300805 return key;
806}
807
808static PyObject *
809uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
810{
811 PyObject *result = PyObject_Call(self->func, args, kwds);
812 if (!result)
813 return NULL;
814 self->misses++;
815 return result;
816}
817
818static PyObject *
819infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
820{
821 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300822 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300823 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
824 if (!key)
825 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300826 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500827 if (hash == -1) {
828 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300829 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500830 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300831 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300832 if (result) {
833 Py_INCREF(result);
834 self->hits++;
835 Py_DECREF(key);
836 return result;
837 }
838 if (PyErr_Occurred()) {
839 Py_DECREF(key);
840 return NULL;
841 }
842 result = PyObject_Call(self->func, args, kwds);
843 if (!result) {
844 Py_DECREF(key);
845 return NULL;
846 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300847 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300848 Py_DECREF(result);
849 Py_DECREF(key);
850 return NULL;
851 }
852 Py_DECREF(key);
853 self->misses++;
854 return result;
855}
856
857static void
858lru_cache_extricate_link(lru_list_elem *link)
859{
860 link->prev->next = link->next;
861 link->next->prev = link->prev;
862}
863
864static void
865lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
866{
867 lru_list_elem *root = &self->root;
868 lru_list_elem *last = root->prev;
869 last->next = root->prev = link;
870 link->prev = last;
871 link->next = root;
872}
873
874static PyObject *
875bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
876{
877 lru_list_elem *link;
878 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300879 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300880
881 key = lru_cache_make_key(args, kwds, self->typed);
882 if (!key)
883 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300884 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500885 if (hash == -1) {
886 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300887 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500888 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300889 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300890 if (link) {
891 lru_cache_extricate_link(link);
892 lru_cache_append_link(self, link);
893 self->hits++;
894 result = link->result;
895 Py_INCREF(result);
896 Py_DECREF(key);
897 return result;
898 }
899 if (PyErr_Occurred()) {
900 Py_DECREF(key);
901 return NULL;
902 }
903 result = PyObject_Call(self->func, args, kwds);
904 if (!result) {
905 Py_DECREF(key);
906 return NULL;
907 }
908 if (self->full && self->root.next != &self->root) {
909 /* Use the oldest item to store the new key and result. */
Serhiy Storchaka67796522017-01-12 18:34:33 +0200910 PyObject *oldkey, *oldresult, *popresult;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300911 /* Extricate the oldest item. */
912 link = self->root.next;
913 lru_cache_extricate_link(link);
914 /* Remove it from the cache.
915 The cache dict holds one reference to the link,
916 and the linked list holds yet one reference to it. */
Serhiy Storchaka42e1ea92017-01-12 19:12:21 +0200917 popresult = _PyDict_Pop_KnownHash(self->cache,
Serhiy Storchaka67796522017-01-12 18:34:33 +0200918 link->key, link->hash,
919 Py_None);
920 if (popresult == Py_None) {
921 /* Getting here means that this same key was added to the
922 cache while the lock was released. Since the link
923 update is already done, we need only return the
924 computed result and update the count of misses. */
925 Py_DECREF(popresult);
926 Py_DECREF(link);
927 Py_DECREF(key);
928 }
929 else if (popresult == NULL) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300930 lru_cache_append_link(self, link);
931 Py_DECREF(key);
932 Py_DECREF(result);
933 return NULL;
934 }
Serhiy Storchaka67796522017-01-12 18:34:33 +0200935 else {
936 Py_DECREF(popresult);
937 /* Keep a reference to the old key and old result to
938 prevent their ref counts from going to zero during the
939 update. That will prevent potentially arbitrary object
940 clean-up code (i.e. __del__) from running while we're
941 still adjusting the links. */
942 oldkey = link->key;
943 oldresult = link->result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300944
Serhiy Storchaka67796522017-01-12 18:34:33 +0200945 link->hash = hash;
946 link->key = key;
947 link->result = result;
948 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
949 hash) < 0) {
950 Py_DECREF(link);
951 Py_DECREF(oldkey);
952 Py_DECREF(oldresult);
953 return NULL;
954 }
955 lru_cache_append_link(self, link);
956 Py_INCREF(result); /* for return */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300957 Py_DECREF(oldkey);
958 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300959 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300960 } else {
961 /* Put result in a new link at the front of the queue. */
962 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
963 &lru_list_elem_type);
964 if (link == NULL) {
965 Py_DECREF(key);
966 Py_DECREF(result);
967 return NULL;
968 }
969
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300970 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300971 link->key = key;
972 link->result = result;
973 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300974 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
975 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300976 Py_DECREF(link);
977 return NULL;
978 }
979 lru_cache_append_link(self, link);
980 Py_INCREF(result); /* for return */
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200981 self->full = (PyDict_GET_SIZE(self->cache) >= self->maxsize);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300982 }
983 self->misses++;
984 return result;
985}
986
987static PyObject *
988lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
989{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300990 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300991 int typed;
992 lru_cache_object *obj;
993 Py_ssize_t maxsize;
994 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
995 static char *keywords[] = {"user_function", "maxsize", "typed",
996 "cache_info_type", NULL};
997
998 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
999 &func, &maxsize_O, &typed,
1000 &cache_info_type)) {
1001 return NULL;
1002 }
1003
1004 if (!PyCallable_Check(func)) {
1005 PyErr_SetString(PyExc_TypeError,
1006 "the first argument must be callable");
1007 return NULL;
1008 }
1009
1010 /* select the caching function, and make/inc maxsize_O */
1011 if (maxsize_O == Py_None) {
1012 wrapper = infinite_lru_cache_wrapper;
1013 /* use this only to initialize lru_cache_object attribute maxsize */
1014 maxsize = -1;
1015 } else if (PyIndex_Check(maxsize_O)) {
1016 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1017 if (maxsize == -1 && PyErr_Occurred())
1018 return NULL;
1019 if (maxsize == 0)
1020 wrapper = uncached_lru_cache_wrapper;
1021 else
1022 wrapper = bounded_lru_cache_wrapper;
1023 } else {
1024 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1025 return NULL;
1026 }
1027
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001028 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001029 return NULL;
1030
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001031 obj = (lru_cache_object *)type->tp_alloc(type, 0);
1032 if (obj == NULL) {
1033 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001034 return NULL;
1035 }
1036
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001037 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001038 obj->root.prev = &obj->root;
1039 obj->root.next = &obj->root;
1040 obj->maxsize = maxsize;
1041 Py_INCREF(maxsize_O);
1042 obj->maxsize_O = maxsize_O;
1043 Py_INCREF(func);
1044 obj->func = func;
1045 obj->wrapper = wrapper;
1046 obj->misses = obj->hits = 0;
1047 obj->typed = typed;
1048 Py_INCREF(cache_info_type);
1049 obj->cache_info_type = cache_info_type;
1050
1051 return (PyObject *)obj;
1052}
1053
1054static lru_list_elem *
1055lru_cache_unlink_list(lru_cache_object *self)
1056{
1057 lru_list_elem *root = &self->root;
1058 lru_list_elem *link = root->next;
1059 if (link == root)
1060 return NULL;
1061 root->prev->next = NULL;
1062 root->next = root->prev = root;
1063 return link;
1064}
1065
1066static void
1067lru_cache_clear_list(lru_list_elem *link)
1068{
1069 while (link != NULL) {
1070 lru_list_elem *next = link->next;
1071 Py_DECREF(link);
1072 link = next;
1073 }
1074}
1075
1076static void
1077lru_cache_dealloc(lru_cache_object *obj)
1078{
INADA Naokia6296d32017-08-24 14:55:17 +09001079 lru_list_elem *list;
1080 /* bpo-31095: UnTrack is needed before calling any callbacks */
1081 PyObject_GC_UnTrack(obj);
1082
1083 list = lru_cache_unlink_list(obj);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001084 Py_XDECREF(obj->maxsize_O);
1085 Py_XDECREF(obj->func);
1086 Py_XDECREF(obj->cache);
1087 Py_XDECREF(obj->dict);
1088 Py_XDECREF(obj->cache_info_type);
1089 lru_cache_clear_list(list);
1090 Py_TYPE(obj)->tp_free(obj);
1091}
1092
1093static PyObject *
1094lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1095{
1096 return self->wrapper(self, args, kwds);
1097}
1098
1099static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001100lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1101{
1102 if (obj == Py_None || obj == NULL) {
1103 Py_INCREF(self);
1104 return self;
1105 }
1106 return PyMethod_New(self, obj);
1107}
1108
1109static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001110lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1111{
1112 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1113 self->hits, self->misses, self->maxsize_O,
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +02001114 PyDict_GET_SIZE(self->cache));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001115}
1116
1117static PyObject *
1118lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1119{
1120 lru_list_elem *list = lru_cache_unlink_list(self);
1121 self->hits = self->misses = 0;
1122 self->full = 0;
1123 PyDict_Clear(self->cache);
1124 lru_cache_clear_list(list);
1125 Py_RETURN_NONE;
1126}
1127
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001128static PyObject *
1129lru_cache_reduce(PyObject *self, PyObject *unused)
1130{
1131 return PyObject_GetAttrString(self, "__qualname__");
1132}
1133
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001134static PyObject *
1135lru_cache_copy(PyObject *self, PyObject *unused)
1136{
1137 Py_INCREF(self);
1138 return self;
1139}
1140
1141static PyObject *
1142lru_cache_deepcopy(PyObject *self, PyObject *unused)
1143{
1144 Py_INCREF(self);
1145 return self;
1146}
1147
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001148static int
1149lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1150{
1151 lru_list_elem *link = self->root.next;
1152 while (link != &self->root) {
1153 lru_list_elem *next = link->next;
1154 Py_VISIT(link);
1155 link = next;
1156 }
1157 Py_VISIT(self->maxsize_O);
1158 Py_VISIT(self->func);
1159 Py_VISIT(self->cache);
1160 Py_VISIT(self->cache_info_type);
1161 Py_VISIT(self->dict);
1162 return 0;
1163}
1164
1165static int
1166lru_cache_tp_clear(lru_cache_object *self)
1167{
1168 lru_list_elem *list = lru_cache_unlink_list(self);
1169 Py_CLEAR(self->maxsize_O);
1170 Py_CLEAR(self->func);
1171 Py_CLEAR(self->cache);
1172 Py_CLEAR(self->cache_info_type);
1173 Py_CLEAR(self->dict);
1174 lru_cache_clear_list(list);
1175 return 0;
1176}
1177
1178
1179PyDoc_STRVAR(lru_cache_doc,
1180"Create a cached callable that wraps another function.\n\
1181\n\
1182user_function: the function being cached\n\
1183\n\
1184maxsize: 0 for no caching\n\
1185 None for unlimited cache size\n\
1186 n for a bounded cache\n\
1187\n\
1188typed: False cache f(3) and f(3.0) as identical calls\n\
1189 True cache f(3) and f(3.0) as distinct calls\n\
1190\n\
1191cache_info_type: namedtuple class with the fields:\n\
1192 hits misses currsize maxsize\n"
1193);
1194
1195static PyMethodDef lru_cache_methods[] = {
1196 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1197 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001198 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001199 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1200 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001201 {NULL}
1202};
1203
1204static PyGetSetDef lru_cache_getsetlist[] = {
1205 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1206 {NULL}
1207};
1208
1209static PyTypeObject lru_cache_type = {
1210 PyVarObject_HEAD_INIT(NULL, 0)
1211 "functools._lru_cache_wrapper", /* tp_name */
1212 sizeof(lru_cache_object), /* tp_basicsize */
1213 0, /* tp_itemsize */
1214 /* methods */
1215 (destructor)lru_cache_dealloc, /* tp_dealloc */
1216 0, /* tp_print */
1217 0, /* tp_getattr */
1218 0, /* tp_setattr */
1219 0, /* tp_reserved */
1220 0, /* tp_repr */
1221 0, /* tp_as_number */
1222 0, /* tp_as_sequence */
1223 0, /* tp_as_mapping */
1224 0, /* tp_hash */
1225 (ternaryfunc)lru_cache_call, /* tp_call */
1226 0, /* tp_str */
1227 0, /* tp_getattro */
1228 0, /* tp_setattro */
1229 0, /* tp_as_buffer */
1230 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1231 /* tp_flags */
1232 lru_cache_doc, /* tp_doc */
1233 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1234 (inquiry)lru_cache_tp_clear, /* tp_clear */
1235 0, /* tp_richcompare */
1236 0, /* tp_weaklistoffset */
1237 0, /* tp_iter */
1238 0, /* tp_iternext */
1239 lru_cache_methods, /* tp_methods */
1240 0, /* tp_members */
1241 lru_cache_getsetlist, /* tp_getset */
1242 0, /* tp_base */
1243 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001244 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001245 0, /* tp_descr_set */
1246 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1247 0, /* tp_init */
1248 0, /* tp_alloc */
1249 lru_cache_new, /* tp_new */
1250};
1251
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001252/* module level code ********************************************************/
1253
1254PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001255"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001256
1257static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001258 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001259 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1260 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001261 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001262};
1263
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001264static void
1265module_free(void *m)
1266{
1267 Py_CLEAR(kwd_mark);
1268}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001269
1270static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001271 PyModuleDef_HEAD_INIT,
1272 "_functools",
1273 module_doc,
1274 -1,
1275 module_methods,
1276 NULL,
1277 NULL,
1278 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001279 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001280};
1281
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001282PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001283PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001284{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001285 int i;
1286 PyObject *m;
Serhiy Storchaka4ab46d72017-09-17 21:11:04 +03001287 const char *name;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001288 PyTypeObject *typelist[] = {
1289 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001290 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001291 NULL
1292 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001293
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001294 m = PyModule_Create(&_functoolsmodule);
1295 if (m == NULL)
1296 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001297
Victor Stinnera5ed5f02016-12-06 18:45:50 +01001298 kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001299 if (!kwd_mark) {
1300 Py_DECREF(m);
1301 return NULL;
1302 }
1303
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001304 for (i=0 ; typelist[i] != NULL ; i++) {
1305 if (PyType_Ready(typelist[i]) < 0) {
1306 Py_DECREF(m);
1307 return NULL;
1308 }
Serhiy Storchaka4ab46d72017-09-17 21:11:04 +03001309 name = _PyType_Name(typelist[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001310 Py_INCREF(typelist[i]);
Serhiy Storchaka4ab46d72017-09-17 21:11:04 +03001311 PyModule_AddObject(m, name, (PyObject *)typelist[i]);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001312 }
1313 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001314}