blob: 218a8d16ac32d9f85a58792121ada3738838c25e [file] [log] [blame]
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001#include "Python.h"
Victor Stinner37834132020-10-27 17:12:53 +01002#include "pycore_long.h" // _PyLong_GetZero()
Victor Stinnercdad2722021-04-22 00:52:52 +02003#include "pycore_moduleobject.h" // _PyModule_GetState()
Brandt Bucher226a0122020-12-04 19:45:57 -08004#include "pycore_object.h" // _PyObject_GC_TRACK
Victor Stinner4a21e572020-04-15 02:35:41 +02005#include "pycore_pystate.h" // _PyThreadState_GET()
Victor Stinner384621c2020-06-22 17:27:35 +02006#include "pycore_tuple.h" // _PyTuple_ITEMS()
Victor Stinner4a21e572020-04-15 02:35:41 +02007#include "structmember.h" // PyMemberDef
Raymond Hettinger9c323f82005-02-28 19:39:44 +00008
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00009/* _functools module written and maintained
Raymond Hettinger9c323f82005-02-28 19:39:44 +000010 by Hye-Shik Chang <perky@FreeBSD.org>
11 with adaptations by Raymond Hettinger <python@rcn.com>
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000012 Copyright (c) 2004, 2005, 2006 Python Software Foundation.
Raymond Hettinger9c323f82005-02-28 19:39:44 +000013 All rights reserved.
14*/
15
Hai Shidd391232020-12-29 20:45:07 +080016typedef struct _functools_state {
17 /* this object is used delimit args and keywords in the cache keys */
18 PyObject *kwd_mark;
19 PyTypeObject *partial_type;
20 PyTypeObject *keyobject_type;
21 PyTypeObject *lru_list_elem_type;
22} _functools_state;
23
24static inline _functools_state *
25get_functools_state(PyObject *module)
26{
Victor Stinnercdad2722021-04-22 00:52:52 +020027 void *state = _PyModule_GetState(module);
Hai Shidd391232020-12-29 20:45:07 +080028 assert(state != NULL);
29 return (_functools_state *)state;
30}
Raymond Hettinger9c323f82005-02-28 19:39:44 +000031
Raymond Hettinger139c2322021-04-21 15:22:22 -070032
33/* partial object **********************************************************/
34
35typedef struct {
36 PyObject_HEAD
37 PyObject *fn;
38 PyObject *args;
39 PyObject *kw;
40 PyObject *dict; /* __dict__ */
41 PyObject *weakreflist; /* List of weak references */
42 vectorcallfunc vectorcall;
43} partialobject;
44
Jeroen Demeyered184c02019-07-13 16:39:18 +020045static void partial_setvectorcall(partialobject *pto);
Hai Shidd391232020-12-29 20:45:07 +080046static struct PyModuleDef _functools_module;
47static PyObject *
48partial_call(partialobject *pto, PyObject *args, PyObject *kwargs);
49
50static inline _functools_state *
51get_functools_state_by_type(PyTypeObject *type)
52{
53 PyObject *module = _PyType_GetModuleByDef(type, &_functools_module);
54 if (module == NULL) {
55 return NULL;
56 }
Victor Stinnercdad2722021-04-22 00:52:52 +020057 return get_functools_state(module);
Hai Shidd391232020-12-29 20:45:07 +080058}
Jeroen Demeyered184c02019-07-13 16:39:18 +020059
Raymond Hettinger9c323f82005-02-28 19:39:44 +000060static PyObject *
61partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
62{
Alexander Belopolskye49af342015-03-01 15:08:17 -050063 PyObject *func, *pargs, *nargs, *pkw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000064 partialobject *pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000065
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000066 if (PyTuple_GET_SIZE(args) < 1) {
67 PyErr_SetString(PyExc_TypeError,
68 "type 'partial' takes at least one argument");
69 return NULL;
70 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000071
Serhiy Storchaka38741282016-02-02 18:45:17 +020072 pargs = pkw = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000073 func = PyTuple_GET_ITEM(args, 0);
Hai Shidd391232020-12-29 20:45:07 +080074 if (Py_TYPE(func)->tp_call == (ternaryfunc)partial_call) {
75 // The type of "func" might not be exactly the same type object
76 // as "type", but if it is called using partial_call, it must have the
77 // same memory layout (fn, args and kw members).
78 // We can use its underlying function directly and merge the arguments.
Alexander Belopolskye49af342015-03-01 15:08:17 -050079 partialobject *part = (partialobject *)func;
80 if (part->dict == NULL) {
81 pargs = part->args;
82 pkw = part->kw;
83 func = part->fn;
Serhiy Storchaka38741282016-02-02 18:45:17 +020084 assert(PyTuple_Check(pargs));
85 assert(PyDict_Check(pkw));
Alexander Belopolskye49af342015-03-01 15:08:17 -050086 }
87 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000088 if (!PyCallable_Check(func)) {
89 PyErr_SetString(PyExc_TypeError,
90 "the first argument must be callable");
91 return NULL;
92 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000093
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000094 /* create partialobject structure */
95 pto = (partialobject *)type->tp_alloc(type, 0);
96 if (pto == NULL)
97 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000098
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000099 pto->fn = func;
100 Py_INCREF(func);
Alexander Belopolskye49af342015-03-01 15:08:17 -0500101
102 nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
103 if (nargs == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 Py_DECREF(pto);
105 return NULL;
106 }
Serhiy Storchaka3c749fc2017-03-25 12:10:16 +0200107 if (pargs == NULL) {
Alexander Belopolskye49af342015-03-01 15:08:17 -0500108 pto->args = nargs;
Alexander Belopolskye49af342015-03-01 15:08:17 -0500109 }
110 else {
111 pto->args = PySequence_Concat(pargs, nargs);
Serhiy Storchaka3c749fc2017-03-25 12:10:16 +0200112 Py_DECREF(nargs);
Alexander Belopolskye49af342015-03-01 15:08:17 -0500113 if (pto->args == NULL) {
Alexander Belopolskye49af342015-03-01 15:08:17 -0500114 Py_DECREF(pto);
115 return NULL;
116 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200117 assert(PyTuple_Check(pto->args));
Alexander Belopolskye49af342015-03-01 15:08:17 -0500118 }
Alexander Belopolskye49af342015-03-01 15:08:17 -0500119
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200120 if (pkw == NULL || PyDict_GET_SIZE(pkw) == 0) {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200121 if (kw == NULL) {
122 pto->kw = PyDict_New();
Alexander Belopolskye49af342015-03-01 15:08:17 -0500123 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +0200124 else if (Py_REFCNT(kw) == 1) {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200125 Py_INCREF(kw);
126 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000127 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +0200128 else {
129 pto->kw = PyDict_Copy(kw);
130 }
Alexander Belopolskye49af342015-03-01 15:08:17 -0500131 }
132 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200133 pto->kw = PyDict_Copy(pkw);
134 if (kw != NULL && pto->kw != NULL) {
135 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -0400136 Py_DECREF(pto);
137 return NULL;
138 }
139 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000140 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200141 if (pto->kw == NULL) {
142 Py_DECREF(pto);
143 return NULL;
144 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000145
Jeroen Demeyered184c02019-07-13 16:39:18 +0200146 partial_setvectorcall(pto);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 return (PyObject *)pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000148}
149
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700150static int
151partial_clear(partialobject *pto)
152{
153 Py_CLEAR(pto->fn);
154 Py_CLEAR(pto->args);
155 Py_CLEAR(pto->kw);
156 Py_CLEAR(pto->dict);
157 return 0;
158}
159
160static int
161partial_traverse(partialobject *pto, visitproc visit, void *arg)
162{
163 Py_VISIT(Py_TYPE(pto));
164 Py_VISIT(pto->fn);
165 Py_VISIT(pto->args);
166 Py_VISIT(pto->kw);
167 Py_VISIT(pto->dict);
168 return 0;
169}
170
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000171static void
172partial_dealloc(partialobject *pto)
173{
Hai Shidd391232020-12-29 20:45:07 +0800174 PyTypeObject *tp = Py_TYPE(pto);
INADA Naokia6296d32017-08-24 14:55:17 +0900175 /* bpo-31095: UnTrack is needed before calling any callbacks */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 PyObject_GC_UnTrack(pto);
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700177 if (pto->weakreflist != NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000178 PyObject_ClearWeakRefs((PyObject *) pto);
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700179 }
180 (void)partial_clear(pto);
Hai Shidd391232020-12-29 20:45:07 +0800181 tp->tp_free(pto);
182 Py_DECREF(tp);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000183}
184
Jeroen Demeyered184c02019-07-13 16:39:18 +0200185
186/* Merging keyword arguments using the vectorcall convention is messy, so
187 * if we would need to do that, we stop using vectorcall and fall back
188 * to using partial_call() instead. */
189_Py_NO_INLINE static PyObject *
Victor Stinner7e433732019-11-08 10:05:17 +0100190partial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto,
191 PyObject *const *args, size_t nargsf,
192 PyObject *kwnames)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000193{
Jeroen Demeyered184c02019-07-13 16:39:18 +0200194 pto->vectorcall = NULL;
195 Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
Victor Stinner7e433732019-11-08 10:05:17 +0100196 return _PyObject_MakeTpCall(tstate, (PyObject *)pto,
197 args, nargs, kwnames);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200198}
199
200static PyObject *
201partial_vectorcall(partialobject *pto, PyObject *const *args,
202 size_t nargsf, PyObject *kwnames)
203{
Victor Stinner7e433732019-11-08 10:05:17 +0100204 PyThreadState *tstate = _PyThreadState_GET();
205
Jeroen Demeyered184c02019-07-13 16:39:18 +0200206 /* pto->kw is mutable, so need to check every time */
207 if (PyDict_GET_SIZE(pto->kw)) {
Victor Stinner7e433732019-11-08 10:05:17 +0100208 return partial_vectorcall_fallback(tstate, pto, args, nargsf, kwnames);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200209 }
210
211 Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
212 Py_ssize_t nargs_total = nargs;
213 if (kwnames != NULL) {
214 nargs_total += PyTuple_GET_SIZE(kwnames);
215 }
216
217 PyObject **pto_args = _PyTuple_ITEMS(pto->args);
218 Py_ssize_t pto_nargs = PyTuple_GET_SIZE(pto->args);
219
220 /* Fast path if we're called without arguments */
221 if (nargs_total == 0) {
Victor Stinner7e433732019-11-08 10:05:17 +0100222 return _PyObject_VectorcallTstate(tstate, pto->fn,
223 pto_args, pto_nargs, NULL);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200224 }
225
226 /* Fast path using PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
227 * positional argument */
228 if (pto_nargs == 1 && (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET)) {
229 PyObject **newargs = (PyObject **)args - 1;
230 PyObject *tmp = newargs[0];
231 newargs[0] = pto_args[0];
Victor Stinner7e433732019-11-08 10:05:17 +0100232 PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn,
233 newargs, nargs + 1, kwnames);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200234 newargs[0] = tmp;
235 return ret;
236 }
237
238 Py_ssize_t newnargs_total = pto_nargs + nargs_total;
239
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100240 PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000241 PyObject *ret;
Jeroen Demeyered184c02019-07-13 16:39:18 +0200242 PyObject **stack;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100243
Jeroen Demeyered184c02019-07-13 16:39:18 +0200244 if (newnargs_total <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
245 stack = small_stack;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100246 }
247 else {
Jeroen Demeyered184c02019-07-13 16:39:18 +0200248 stack = PyMem_Malloc(newnargs_total * sizeof(PyObject *));
249 if (stack == NULL) {
250 PyErr_NoMemory();
251 return NULL;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100252 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100253 }
254
Jeroen Demeyered184c02019-07-13 16:39:18 +0200255 /* Copy to new stack, using borrowed references */
256 memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
257 memcpy(stack + pto_nargs, args, nargs_total * sizeof(PyObject*));
258
Victor Stinner7e433732019-11-08 10:05:17 +0100259 ret = _PyObject_VectorcallTstate(tstate, pto->fn,
260 stack, pto_nargs + nargs, kwnames);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200261 if (stack != small_stack) {
262 PyMem_Free(stack);
263 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100264 return ret;
265}
266
Jeroen Demeyered184c02019-07-13 16:39:18 +0200267/* Set pto->vectorcall depending on the parameters of the partial object */
268static void
269partial_setvectorcall(partialobject *pto)
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100270{
Petr Viktorinffd97532020-02-11 17:46:57 +0100271 if (PyVectorcall_Function(pto->fn) == NULL) {
Jeroen Demeyered184c02019-07-13 16:39:18 +0200272 /* Don't use vectorcall if the underlying function doesn't support it */
273 pto->vectorcall = NULL;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100274 }
Jeroen Demeyered184c02019-07-13 16:39:18 +0200275 /* We could have a special case if there are no arguments,
276 * but that is unlikely (why use partial without arguments?),
277 * so we don't optimize that */
278 else {
279 pto->vectorcall = (vectorcallfunc)partial_vectorcall;
280 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100281}
282
Jeroen Demeyered184c02019-07-13 16:39:18 +0200283
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100284static PyObject *
285partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
286{
Jeroen Demeyered184c02019-07-13 16:39:18 +0200287 assert(PyCallable_Check(pto->fn));
288 assert(PyTuple_Check(pto->args));
289 assert(PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000290
Jeroen Demeyered184c02019-07-13 16:39:18 +0200291 /* Merge keywords */
292 PyObject *kwargs2;
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200293 if (PyDict_GET_SIZE(pto->kw) == 0) {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100294 /* kwargs can be NULL */
295 kwargs2 = kwargs;
296 Py_XINCREF(kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200297 }
298 else {
Victor Stinner561ca802017-02-23 18:26:43 +0100299 /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
300 copied, because a function using "**kwargs" can modify the
301 dictionary. */
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100302 kwargs2 = PyDict_Copy(pto->kw);
303 if (kwargs2 == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000304 return NULL;
305 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200306
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100307 if (kwargs != NULL) {
308 if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
309 Py_DECREF(kwargs2);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000310 return NULL;
311 }
312 }
313 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000314
Jeroen Demeyered184c02019-07-13 16:39:18 +0200315 /* Merge positional arguments */
316 /* Note: tupleconcat() is optimized for empty tuples */
317 PyObject *args2 = PySequence_Concat(pto->args, args);
318 if (args2 == NULL) {
319 Py_XDECREF(kwargs2);
320 return NULL;
321 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100322
Jeroen Demeyered184c02019-07-13 16:39:18 +0200323 PyObject *res = PyObject_Call(pto->fn, args2, kwargs2);
324 Py_DECREF(args2);
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100325 Py_XDECREF(kwargs2);
326 return res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000327}
328
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000329PyDoc_STRVAR(partial_doc,
330"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000332
333#define OFF(x) offsetof(partialobject, x)
334static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000335 {"func", T_OBJECT, OFF(fn), READONLY,
336 "function object to use in future partial calls"},
337 {"args", T_OBJECT, OFF(args), READONLY,
338 "tuple of arguments to future partial calls"},
339 {"keywords", T_OBJECT, OFF(kw), READONLY,
340 "dictionary of keyword arguments to future partial calls"},
Hai Shidd391232020-12-29 20:45:07 +0800341 {"__weaklistoffset__", T_PYSSIZET,
342 offsetof(partialobject, weakreflist), READONLY},
343 {"__dictoffset__", T_PYSSIZET,
344 offsetof(partialobject, dict), READONLY},
345 {"__vectorcalloffset__", T_PYSSIZET,
346 offsetof(partialobject, vectorcall), READONLY},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000348};
349
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000350static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500351 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000353};
354
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000355static PyObject *
356partial_repr(partialobject *pto)
357{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300358 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000359 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000360 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200361 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300362 int status;
363
364 status = Py_ReprEnter((PyObject *)pto);
365 if (status != 0) {
366 if (status < 0)
367 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000368 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300369 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000370
371 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300372 if (arglist == NULL)
373 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000374 /* Pack positional arguments */
375 assert (PyTuple_Check(pto->args));
376 n = PyTuple_GET_SIZE(pto->args);
377 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300378 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
379 PyTuple_GET_ITEM(pto->args, i)));
380 if (arglist == NULL)
381 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000382 }
383 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200384 assert (PyDict_Check(pto->kw));
385 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Michael Seifert6c3d5272017-03-15 06:26:33 +0100386 /* Prevent key.__str__ from deleting the value. */
387 Py_INCREF(value);
388 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300389 key, value));
Michael Seifert6c3d5272017-03-15 06:26:33 +0100390 Py_DECREF(value);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300391 if (arglist == NULL)
392 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000393 }
394 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
395 pto->fn, arglist);
396 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300397
398 done:
399 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000400 return result;
401}
402
Jack Diederiche0cbd692009-04-01 04:27:09 +0000403/* Pickle strategy:
404 __reduce__ by itself doesn't support getting kwargs in the unpickle
405 operation so we define a __setstate__ that replaces all the information
406 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200407 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000408 */
409
Antoine Pitrou69f71142009-05-24 21:25:49 +0000410static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000411partial_reduce(partialobject *pto, PyObject *unused)
412{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000413 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
414 pto->args, pto->kw,
415 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000416}
417
Antoine Pitrou69f71142009-05-24 21:25:49 +0000418static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200419partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000420{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000421 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200422
423 if (!PyTuple_Check(state) ||
424 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
425 !PyCallable_Check(fn) ||
426 !PyTuple_Check(fnargs) ||
427 (kw != Py_None && !PyDict_Check(kw)))
428 {
429 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200432
433 if(!PyTuple_CheckExact(fnargs))
434 fnargs = PySequence_Tuple(fnargs);
435 else
436 Py_INCREF(fnargs);
437 if (fnargs == NULL)
438 return NULL;
439
440 if (kw == Py_None)
441 kw = PyDict_New();
442 else if(!PyDict_CheckExact(kw))
443 kw = PyDict_Copy(kw);
444 else
445 Py_INCREF(kw);
446 if (kw == NULL) {
447 Py_DECREF(fnargs);
448 return NULL;
449 }
450
Serhiy Storchaka38741282016-02-02 18:45:17 +0200451 if (dict == Py_None)
452 dict = NULL;
453 else
454 Py_INCREF(dict);
455
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100456 Py_INCREF(fn);
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300457 Py_SETREF(pto->fn, fn);
458 Py_SETREF(pto->args, fnargs);
459 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300460 Py_XSETREF(pto->dict, dict);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200461 partial_setvectorcall(pto);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000463}
464
465static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000466 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200467 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Ethan Smithcecf0492020-04-13 21:53:04 -0700468 {"__class_getitem__", (PyCFunction)Py_GenericAlias,
469 METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000471};
472
Hai Shidd391232020-12-29 20:45:07 +0800473static PyType_Slot partial_type_slots[] = {
474 {Py_tp_dealloc, partial_dealloc},
475 {Py_tp_repr, partial_repr},
476 {Py_tp_call, partial_call},
477 {Py_tp_getattro, PyObject_GenericGetAttr},
478 {Py_tp_setattro, PyObject_GenericSetAttr},
479 {Py_tp_doc, (void *)partial_doc},
480 {Py_tp_traverse, partial_traverse},
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700481 {Py_tp_clear, partial_clear},
Hai Shidd391232020-12-29 20:45:07 +0800482 {Py_tp_methods, partial_methods},
483 {Py_tp_members, partial_memberlist},
484 {Py_tp_getset, partial_getsetlist},
485 {Py_tp_new, partial_new},
486 {Py_tp_free, PyObject_GC_Del},
487 {0, 0}
488};
489
490static PyType_Spec partial_type_spec = {
491 .name = "functools.partial",
492 .basicsize = sizeof(partialobject),
493 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
494 Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
495 .slots = partial_type_slots
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000496};
497
498
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700499/* cmp_to_key ***************************************************************/
500
501typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200502 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700503 PyObject *cmp;
504 PyObject *object;
505} keyobject;
506
Hai Shidd391232020-12-29 20:45:07 +0800507static int
508keyobject_clear(keyobject *ko)
509{
510 Py_CLEAR(ko->cmp);
511 Py_CLEAR(ko->object);
512 return 0;
513}
514
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700515static void
516keyobject_dealloc(keyobject *ko)
517{
Hai Shidd391232020-12-29 20:45:07 +0800518 PyTypeObject *tp = Py_TYPE(ko);
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700519 PyObject_GC_UnTrack(ko);
520 (void)keyobject_clear(ko);
521 tp->tp_free(ko);
Hai Shidd391232020-12-29 20:45:07 +0800522 Py_DECREF(tp);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700523}
524
525static int
526keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
527{
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700528 Py_VISIT(Py_TYPE(ko));
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700529 Py_VISIT(ko->cmp);
Hai Shi47a23fc2020-06-07 20:05:36 +0800530 Py_VISIT(ko->object);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700531 return 0;
532}
533
534static PyMemberDef keyobject_members[] = {
535 {"obj", T_OBJECT,
536 offsetof(keyobject, object), 0,
537 PyDoc_STR("Value wrapped by a key function.")},
538 {NULL}
539};
540
541static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700542keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700543
544static PyObject *
545keyobject_richcompare(PyObject *ko, PyObject *other, int op);
546
Hai Shidd391232020-12-29 20:45:07 +0800547static PyType_Slot keyobject_type_slots[] = {
548 {Py_tp_dealloc, keyobject_dealloc},
549 {Py_tp_call, keyobject_call},
550 {Py_tp_getattro, PyObject_GenericGetAttr},
551 {Py_tp_traverse, keyobject_traverse},
552 {Py_tp_clear, keyobject_clear},
553 {Py_tp_richcompare, keyobject_richcompare},
554 {Py_tp_members, keyobject_members},
555 {0, 0}
556};
557
558static PyType_Spec keyobject_type_spec = {
559 .name = "functools.KeyWrapper",
560 .basicsize = sizeof(keyobject),
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700561 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
562 Py_TPFLAGS_HAVE_GC),
Hai Shidd391232020-12-29 20:45:07 +0800563 .slots = keyobject_type_slots
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700564};
565
566static PyObject *
567keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
568{
569 PyObject *object;
570 keyobject *result;
571 static char *kwargs[] = {"obj", NULL};
572
573 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
574 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800575
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700576 result = PyObject_GC_New(keyobject, Py_TYPE(ko));
Hai Shidd391232020-12-29 20:45:07 +0800577 if (result == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700578 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800579 }
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700580 Py_INCREF(ko->cmp);
581 result->cmp = ko->cmp;
582 Py_INCREF(object);
583 result->object = object;
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700584 PyObject_GC_Track(result);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700585 return (PyObject *)result;
586}
587
588static PyObject *
589keyobject_richcompare(PyObject *ko, PyObject *other, int op)
590{
591 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700592 PyObject *x;
593 PyObject *y;
594 PyObject *compare;
595 PyObject *answer;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200596 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700597
Hai Shidd391232020-12-29 20:45:07 +0800598 if (!Py_IS_TYPE(other, Py_TYPE(ko))) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700599 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
600 return NULL;
601 }
602 compare = ((keyobject *) ko)->cmp;
603 assert(compare != NULL);
604 x = ((keyobject *) ko)->object;
605 y = ((keyobject *) other)->object;
606 if (!x || !y){
607 PyErr_Format(PyExc_AttributeError, "object");
608 return NULL;
609 }
610
611 /* Call the user's comparison function and translate the 3-way
612 * result into true or false (or error).
613 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200614 stack[0] = x;
615 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200616 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200617 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700618 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200619 }
620
Victor Stinner37834132020-10-27 17:12:53 +0100621 answer = PyObject_RichCompare(res, _PyLong_GetZero(), op);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700622 Py_DECREF(res);
623 return answer;
624}
625
626static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200627functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
628{
629 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700630 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200631 keyobject *object;
Hai Shidd391232020-12-29 20:45:07 +0800632 _functools_state *state;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700633
634 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
635 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800636
637 state = get_functools_state(self);
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700638 object = PyObject_GC_New(keyobject, state->keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700639 if (!object)
640 return NULL;
641 Py_INCREF(cmp);
642 object->cmp = cmp;
643 object->object = NULL;
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700644 PyObject_GC_Track(object);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700645 return (PyObject *)object;
646}
647
648PyDoc_STRVAR(functools_cmp_to_key_doc,
649"Convert a cmp= function into a key= function.");
650
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000651/* reduce (used to be a builtin) ********************************************/
652
653static PyObject *
654functools_reduce(PyObject *self, PyObject *args)
655{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000656 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000657
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000658 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
659 return NULL;
660 if (result != NULL)
661 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000662
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000663 it = PyObject_GetIter(seq);
664 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000665 if (PyErr_ExceptionMatches(PyExc_TypeError))
666 PyErr_SetString(PyExc_TypeError,
667 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000668 Py_XDECREF(result);
669 return NULL;
670 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000671
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000672 if ((args = PyTuple_New(2)) == NULL)
673 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000674
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000675 for (;;) {
676 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000677
Victor Stinnera93c51e2020-02-07 00:38:59 +0100678 if (Py_REFCNT(args) > 1) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000679 Py_DECREF(args);
680 if ((args = PyTuple_New(2)) == NULL)
681 goto Fail;
682 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000683
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000684 op2 = PyIter_Next(it);
685 if (op2 == NULL) {
686 if (PyErr_Occurred())
687 goto Fail;
688 break;
689 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000690
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000691 if (result == NULL)
692 result = op2;
693 else {
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500694 /* Update the args tuple in-place */
Victor Stinnera93c51e2020-02-07 00:38:59 +0100695 assert(Py_REFCNT(args) == 1);
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500696 Py_XSETREF(_PyTuple_ITEMS(args)[0], result);
697 Py_XSETREF(_PyTuple_ITEMS(args)[1], op2);
698 if ((result = PyObject_Call(func, args, NULL)) == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000699 goto Fail;
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500700 }
Brandt Bucher226a0122020-12-04 19:45:57 -0800701 // bpo-42536: The GC may have untracked this args tuple. Since we're
702 // recycling it, make sure it's tracked again:
703 if (!_PyObject_GC_IS_TRACKED(args)) {
704 _PyObject_GC_TRACK(args);
705 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000706 }
707 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000708
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000709 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000710
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000711 if (result == NULL)
712 PyErr_SetString(PyExc_TypeError,
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600713 "reduce() of empty iterable with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000714
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000715 Py_DECREF(it);
716 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000717
718Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000719 Py_XDECREF(args);
720 Py_XDECREF(result);
721 Py_DECREF(it);
722 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000723}
724
725PyDoc_STRVAR(functools_reduce_doc,
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600726"reduce(function, iterable[, initial]) -> value\n\
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000727\n\
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600728Apply a function of two arguments cumulatively to the items of a sequence\n\
729or iterable, from left to right, so as to reduce the iterable to a single\n\
730value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000731((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600732of the iterable in the calculation, and serves as a default when the\n\
733iterable is empty.");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000734
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300735/* lru_cache object **********************************************************/
736
Raymond Hettinger2dda72a2019-02-08 18:55:02 -0800737/* There are four principal algorithmic differences from the pure python version:
738
739 1). The C version relies on the GIL instead of having its own reentrant lock.
740
741 2). The prev/next link fields use borrowed references.
742
743 3). For a full cache, the pure python version rotates the location of the
744 root entry so that it never has to move individual links and it can
745 limit updates to just the key and result fields. However, in the C
746 version, links are temporarily removed while the cache dict updates are
747 occurring. Afterwards, they are appended or prepended back into the
748 doubly-linked lists.
749
750 4) In the Python version, the _HashSeq class is used to prevent __hash__
751 from being called more than once. In the C version, the "known hash"
752 variants of dictionary calls as used to the same effect.
753
754*/
755
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300756struct lru_list_elem;
757struct lru_cache_object;
758
759typedef struct lru_list_elem {
760 PyObject_HEAD
761 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300762 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300763 PyObject *key, *result;
764} lru_list_elem;
765
766static void
767lru_list_elem_dealloc(lru_list_elem *link)
768{
Hai Shidd391232020-12-29 20:45:07 +0800769 PyTypeObject *tp = Py_TYPE(link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300770 Py_XDECREF(link->key);
771 Py_XDECREF(link->result);
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700772 tp->tp_free(link);
Hai Shidd391232020-12-29 20:45:07 +0800773 Py_DECREF(tp);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300774}
775
Hai Shidd391232020-12-29 20:45:07 +0800776static PyType_Slot lru_list_elem_type_slots[] = {
777 {Py_tp_dealloc, lru_list_elem_dealloc},
778 {0, 0}
779};
780
781static PyType_Spec lru_list_elem_type_spec = {
782 .name = "functools._lru_list_elem",
783 .basicsize = sizeof(lru_list_elem),
Erlend Egeberg Aasland9746cda2021-04-30 16:04:57 +0200784 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
Hai Shidd391232020-12-29 20:45:07 +0800785 .slots = lru_list_elem_type_slots
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300786};
787
788
789typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
790
791typedef struct lru_cache_object {
792 lru_list_elem root; /* includes PyObject_HEAD */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300793 lru_cache_ternaryfunc wrapper;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300794 int typed;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500795 PyObject *cache;
796 Py_ssize_t hits;
797 PyObject *func;
798 Py_ssize_t maxsize;
799 Py_ssize_t misses;
Raymond Hettinger139c2322021-04-21 15:22:22 -0700800 /* the kwd_mark is used delimit args and keywords in the cache keys */
801 PyObject *kwd_mark;
802 PyTypeObject *lru_list_elem_type;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500803 PyObject *cache_info_type;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300804 PyObject *dict;
Dennis Sweeney1253c3e2020-05-05 17:14:32 -0400805 PyObject *weakreflist;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300806} lru_cache_object;
807
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300808static PyObject *
Raymond Hettinger139c2322021-04-21 15:22:22 -0700809lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
Hai Shidd391232020-12-29 20:45:07 +0800810 PyObject *kwds, int typed)
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300811{
Raymond Hettingerdda44682017-01-08 18:04:30 -0800812 PyObject *key, *keyword, *value;
813 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300814
Raymond Hettinger14adbd42019-04-20 07:20:44 -1000815 kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
816
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300817 /* short path, key will match args anyway, which is a tuple */
Raymond Hettinger14adbd42019-04-20 07:20:44 -1000818 if (!typed && !kwds_size) {
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500819 if (PyTuple_GET_SIZE(args) == 1) {
820 key = PyTuple_GET_ITEM(args, 0);
821 if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) {
822 /* For common scalar keys, save space by
823 dropping the enclosing args tuple */
824 Py_INCREF(key);
825 return key;
826 }
827 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300828 Py_INCREF(args);
829 return args;
830 }
831
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300832 key_size = PyTuple_GET_SIZE(args);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800833 if (kwds_size)
834 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300835 if (typed)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800836 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300837
838 key = PyTuple_New(key_size);
839 if (key == NULL)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800840 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300841
842 key_pos = 0;
843 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
844 PyObject *item = PyTuple_GET_ITEM(args, pos);
845 Py_INCREF(item);
846 PyTuple_SET_ITEM(key, key_pos++, item);
847 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800848 if (kwds_size) {
Raymond Hettinger139c2322021-04-21 15:22:22 -0700849 Py_INCREF(kwd_mark);
850 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800851 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
852 Py_INCREF(keyword);
853 PyTuple_SET_ITEM(key, key_pos++, keyword);
854 Py_INCREF(value);
855 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300856 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800857 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300858 }
859 if (typed) {
860 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
861 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
862 Py_INCREF(item);
863 PyTuple_SET_ITEM(key, key_pos++, item);
864 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800865 if (kwds_size) {
866 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
867 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300868 Py_INCREF(item);
869 PyTuple_SET_ITEM(key, key_pos++, item);
870 }
871 }
872 }
873 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300874 return key;
875}
876
877static PyObject *
878uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
879{
Raymond Hettingerffdf1c32019-01-31 15:03:38 -0800880 PyObject *result;
881
882 self->misses++;
883 result = PyObject_Call(self->func, args, kwds);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300884 if (!result)
885 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300886 return result;
887}
888
889static PyObject *
890infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
891{
892 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300893 Py_hash_t hash;
Raymond Hettinger139c2322021-04-21 15:22:22 -0700894 PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300895 if (!key)
896 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300897 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500898 if (hash == -1) {
899 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300900 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500901 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300902 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300903 if (result) {
904 Py_INCREF(result);
905 self->hits++;
906 Py_DECREF(key);
907 return result;
908 }
909 if (PyErr_Occurred()) {
910 Py_DECREF(key);
911 return NULL;
912 }
Raymond Hettingerffdf1c32019-01-31 15:03:38 -0800913 self->misses++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300914 result = PyObject_Call(self->func, args, kwds);
915 if (!result) {
916 Py_DECREF(key);
917 return NULL;
918 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300919 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300920 Py_DECREF(result);
921 Py_DECREF(key);
922 return NULL;
923 }
924 Py_DECREF(key);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300925 return result;
926}
927
928static void
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500929lru_cache_extract_link(lru_list_elem *link)
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300930{
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500931 lru_list_elem *link_prev = link->prev;
932 lru_list_elem *link_next = link->next;
933 link_prev->next = link->next;
934 link_next->prev = link->prev;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300935}
936
937static void
938lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
939{
940 lru_list_elem *root = &self->root;
941 lru_list_elem *last = root->prev;
942 last->next = root->prev = link;
943 link->prev = last;
944 link->next = root;
945}
946
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500947static void
948lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
949{
950 lru_list_elem *root = &self->root;
951 lru_list_elem *first = root->next;
952 first->prev = root->next = link;
953 link->prev = root;
954 link->next = first;
955}
956
957/* General note on reentrancy:
958
959 There are four dictionary calls in the bounded_lru_cache_wrapper():
960 1) The initial check for a cache match. 2) The post user-function
961 check for a cache match. 3) The deletion of the oldest entry.
962 4) The addition of the newest entry.
963
964 In all four calls, we have a known hash which lets use avoid a call
965 to __hash__(). That leaves only __eq__ as a possible source of a
966 reentrant call.
967
968 The __eq__ method call is always made for a cache hit (dict access #1).
969 Accordingly, we have make sure not modify the cache state prior to
970 this call.
971
972 The __eq__ method call is never made for the deletion (dict access #3)
973 because it is an identity match.
974
975 For the other two accesses (#2 and #4), calls to __eq__ only occur
976 when some other entry happens to have an exactly matching hash (all
977 64-bits). Though rare, this can happen, so we have to make sure to
978 either call it at the top of its code path before any cache
979 state modifications (dict access #2) or be prepared to restore
980 invariants at the end of the code path (dict access #4).
981
982 Another possible source of reentrancy is a decref which can trigger
983 arbitrary code execution. To make the code easier to reason about,
984 the decrefs are deferred to the end of the each possible code path
985 so that we know the cache is a consistent state.
986 */
987
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300988static PyObject *
989bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
990{
991 lru_list_elem *link;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500992 PyObject *key, *result, *testresult;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300993 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300994
Raymond Hettinger139c2322021-04-21 15:22:22 -0700995 key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300996 if (!key)
997 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300998 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500999 if (hash == -1) {
1000 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001001 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -05001002 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001003 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001004 if (link != NULL) {
1005 lru_cache_extract_link(link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001006 lru_cache_append_link(self, link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001007 result = link->result;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001008 self->hits++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001009 Py_INCREF(result);
1010 Py_DECREF(key);
1011 return result;
1012 }
1013 if (PyErr_Occurred()) {
1014 Py_DECREF(key);
1015 return NULL;
1016 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001017 self->misses++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001018 result = PyObject_Call(self->func, args, kwds);
1019 if (!result) {
1020 Py_DECREF(key);
1021 return NULL;
1022 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001023 testresult = _PyDict_GetItem_KnownHash(self->cache, key, hash);
1024 if (testresult != NULL) {
1025 /* Getting here means that this same key was added to the cache
1026 during the PyObject_Call(). Since the link update is already
1027 done, we need only return the computed result. */
1028 Py_DECREF(key);
1029 return result;
1030 }
1031 if (PyErr_Occurred()) {
1032 /* This is an unusual case since this same lookup
1033 did not previously trigger an error during lookup.
1034 Treat it the same as an error in user function
1035 and return with the error set. */
1036 Py_DECREF(key);
1037 Py_DECREF(result);
1038 return NULL;
1039 }
1040 /* This is the normal case. The new key wasn't found before
1041 user function call and it is still not there. So we
1042 proceed normally and update the cache with the new result. */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001043
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001044 assert(self->maxsize > 0);
1045 if (PyDict_GET_SIZE(self->cache) < self->maxsize ||
1046 self->root.next == &self->root)
1047 {
1048 /* Cache is not full, so put the result in a new link */
INADA Naoki3070b712017-12-26 02:03:24 +09001049 link = (lru_list_elem *)PyObject_New(lru_list_elem,
Raymond Hettinger139c2322021-04-21 15:22:22 -07001050 self->lru_list_elem_type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001051 if (link == NULL) {
1052 Py_DECREF(key);
1053 Py_DECREF(result);
1054 return NULL;
1055 }
1056
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001057 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001058 link->key = key;
1059 link->result = result;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001060 /* What is really needed here is a SetItem variant with a "no clobber"
1061 option. If the __eq__ call triggers a reentrant call that adds
1062 this same key, then this setitem call will update the cache dict
1063 with this new link, leaving the old link as an orphan (i.e. not
1064 having a cache dict entry that refers to it). */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001065 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
1066 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001067 Py_DECREF(link);
1068 return NULL;
1069 }
1070 lru_cache_append_link(self, link);
1071 Py_INCREF(result); /* for return */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001072 return result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001073 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001074 /* Since the cache is full, we need to evict an old key and add
1075 a new key. Rather than free the old link and allocate a new
1076 one, we reuse the link for the new key and result and move it
1077 to front of the cache to mark it as recently used.
1078
1079 We try to assure all code paths (including errors) leave all
1080 of the links in place. Either the link is successfully
1081 updated and moved or it is restored to its old position.
1082 However if an unrecoverable error is found, it doesn't
1083 make sense to reinsert the link, so we leave it out
1084 and the cache will no longer register as full.
1085 */
1086 PyObject *oldkey, *oldresult, *popresult;
1087
1088 /* Extract the oldest item. */
1089 assert(self->root.next != &self->root);
1090 link = self->root.next;
1091 lru_cache_extract_link(link);
1092 /* Remove it from the cache.
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001093 The cache dict holds one reference to the link.
1094 We created one other reference when the link was created.
1095 The linked list only has borrowed references. */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001096 popresult = _PyDict_Pop_KnownHash(self->cache, link->key,
1097 link->hash, Py_None);
1098 if (popresult == Py_None) {
1099 /* Getting here means that the user function call or another
1100 thread has already removed the old key from the dictionary.
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001101 This link is now an orphan. Since we don't want to leave the
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001102 cache in an inconsistent state, we don't restore the link. */
1103 Py_DECREF(popresult);
1104 Py_DECREF(link);
1105 Py_DECREF(key);
1106 return result;
1107 }
1108 if (popresult == NULL) {
1109 /* An error arose while trying to remove the oldest key (the one
1110 being evicted) from the cache. We restore the link to its
1111 original position as the oldest link. Then we allow the
1112 error propagate upward; treating it the same as an error
1113 arising in the user function. */
1114 lru_cache_prepend_link(self, link);
1115 Py_DECREF(key);
1116 Py_DECREF(result);
1117 return NULL;
1118 }
1119 /* Keep a reference to the old key and old result to prevent their
1120 ref counts from going to zero during the update. That will
1121 prevent potentially arbitrary object clean-up code (i.e. __del__)
1122 from running while we're still adjusting the links. */
1123 oldkey = link->key;
1124 oldresult = link->result;
1125
1126 link->hash = hash;
1127 link->key = key;
1128 link->result = result;
1129 /* Note: The link is being added to the cache dict without the
1130 prev and next fields set to valid values. We have to wait
1131 for successful insertion in the cache dict before adding the
1132 link to the linked list. Otherwise, the potentially reentrant
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001133 __eq__ call could cause the then orphan link to be visited. */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001134 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
1135 hash) < 0) {
1136 /* Somehow the cache dict update failed. We no longer can
1137 restore the old link. Let the error propagate upward and
1138 leave the cache short one link. */
1139 Py_DECREF(popresult);
1140 Py_DECREF(link);
1141 Py_DECREF(oldkey);
1142 Py_DECREF(oldresult);
1143 return NULL;
1144 }
1145 lru_cache_append_link(self, link);
1146 Py_INCREF(result); /* for return */
1147 Py_DECREF(popresult);
1148 Py_DECREF(oldkey);
1149 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001150 return result;
1151}
1152
1153static PyObject *
1154lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
1155{
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001156 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001157 int typed;
1158 lru_cache_object *obj;
1159 Py_ssize_t maxsize;
1160 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
Raymond Hettinger139c2322021-04-21 15:22:22 -07001161 _functools_state *state;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001162 static char *keywords[] = {"user_function", "maxsize", "typed",
1163 "cache_info_type", NULL};
1164
1165 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
1166 &func, &maxsize_O, &typed,
1167 &cache_info_type)) {
1168 return NULL;
1169 }
1170
1171 if (!PyCallable_Check(func)) {
1172 PyErr_SetString(PyExc_TypeError,
1173 "the first argument must be callable");
1174 return NULL;
1175 }
1176
Raymond Hettinger139c2322021-04-21 15:22:22 -07001177 state = get_functools_state_by_type(type);
1178 if (state == NULL) {
1179 return NULL;
1180 }
1181
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001182 /* select the caching function, and make/inc maxsize_O */
1183 if (maxsize_O == Py_None) {
1184 wrapper = infinite_lru_cache_wrapper;
1185 /* use this only to initialize lru_cache_object attribute maxsize */
1186 maxsize = -1;
1187 } else if (PyIndex_Check(maxsize_O)) {
1188 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1189 if (maxsize == -1 && PyErr_Occurred())
1190 return NULL;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001191 if (maxsize < 0) {
1192 maxsize = 0;
1193 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001194 if (maxsize == 0)
1195 wrapper = uncached_lru_cache_wrapper;
1196 else
1197 wrapper = bounded_lru_cache_wrapper;
1198 } else {
1199 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1200 return NULL;
1201 }
1202
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001203 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001204 return NULL;
1205
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001206 obj = (lru_cache_object *)type->tp_alloc(type, 0);
1207 if (obj == NULL) {
1208 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001209 return NULL;
1210 }
1211
1212 obj->root.prev = &obj->root;
1213 obj->root.next = &obj->root;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001214 obj->wrapper = wrapper;
1215 obj->typed = typed;
1216 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001217 Py_INCREF(func);
1218 obj->func = func;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001219 obj->misses = obj->hits = 0;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001220 obj->maxsize = maxsize;
Raymond Hettinger139c2322021-04-21 15:22:22 -07001221 Py_INCREF(state->kwd_mark);
1222 obj->kwd_mark = state->kwd_mark;
1223 Py_INCREF(state->lru_list_elem_type);
1224 obj->lru_list_elem_type = state->lru_list_elem_type;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001225 Py_INCREF(cache_info_type);
1226 obj->cache_info_type = cache_info_type;
Raymond Hettingerbba760e2020-04-20 13:47:12 -07001227 obj->dict = NULL;
Dennis Sweeney1253c3e2020-05-05 17:14:32 -04001228 obj->weakreflist = NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001229 return (PyObject *)obj;
1230}
1231
1232static lru_list_elem *
1233lru_cache_unlink_list(lru_cache_object *self)
1234{
1235 lru_list_elem *root = &self->root;
1236 lru_list_elem *link = root->next;
1237 if (link == root)
1238 return NULL;
1239 root->prev->next = NULL;
1240 root->next = root->prev = root;
1241 return link;
1242}
1243
1244static void
1245lru_cache_clear_list(lru_list_elem *link)
1246{
1247 while (link != NULL) {
1248 lru_list_elem *next = link->next;
1249 Py_DECREF(link);
1250 link = next;
1251 }
1252}
1253
Hai Shidd391232020-12-29 20:45:07 +08001254static int
1255lru_cache_tp_clear(lru_cache_object *self)
1256{
1257 lru_list_elem *list = lru_cache_unlink_list(self);
Hai Shidd391232020-12-29 20:45:07 +08001258 Py_CLEAR(self->cache);
Miss Islington (bot)1c0106c2021-05-28 07:26:07 -07001259 Py_CLEAR(self->func);
Raymond Hettinger139c2322021-04-21 15:22:22 -07001260 Py_CLEAR(self->kwd_mark);
1261 Py_CLEAR(self->lru_list_elem_type);
Hai Shidd391232020-12-29 20:45:07 +08001262 Py_CLEAR(self->cache_info_type);
1263 Py_CLEAR(self->dict);
1264 lru_cache_clear_list(list);
1265 return 0;
1266}
1267
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001268static void
1269lru_cache_dealloc(lru_cache_object *obj)
1270{
Hai Shidd391232020-12-29 20:45:07 +08001271 PyTypeObject *tp = Py_TYPE(obj);
INADA Naokia6296d32017-08-24 14:55:17 +09001272 /* bpo-31095: UnTrack is needed before calling any callbacks */
1273 PyObject_GC_UnTrack(obj);
Hai Shidd391232020-12-29 20:45:07 +08001274 if (obj->weakreflist != NULL) {
Dennis Sweeney1253c3e2020-05-05 17:14:32 -04001275 PyObject_ClearWeakRefs((PyObject*)obj);
Hai Shidd391232020-12-29 20:45:07 +08001276 }
INADA Naokia6296d32017-08-24 14:55:17 +09001277
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -07001278 (void)lru_cache_tp_clear(obj);
Hai Shidd391232020-12-29 20:45:07 +08001279 tp->tp_free(obj);
1280 Py_DECREF(tp);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001281}
1282
1283static PyObject *
1284lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1285{
1286 return self->wrapper(self, args, kwds);
1287}
1288
1289static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001290lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1291{
1292 if (obj == Py_None || obj == NULL) {
1293 Py_INCREF(self);
1294 return self;
1295 }
1296 return PyMethod_New(self, obj);
1297}
1298
1299static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001300lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1301{
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001302 if (self->maxsize == -1) {
1303 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1304 self->hits, self->misses, Py_None,
1305 PyDict_GET_SIZE(self->cache));
1306 }
1307 return PyObject_CallFunction(self->cache_info_type, "nnnn",
1308 self->hits, self->misses, self->maxsize,
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +02001309 PyDict_GET_SIZE(self->cache));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001310}
1311
1312static PyObject *
1313lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1314{
1315 lru_list_elem *list = lru_cache_unlink_list(self);
1316 self->hits = self->misses = 0;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001317 PyDict_Clear(self->cache);
1318 lru_cache_clear_list(list);
1319 Py_RETURN_NONE;
1320}
1321
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001322static PyObject *
1323lru_cache_reduce(PyObject *self, PyObject *unused)
1324{
1325 return PyObject_GetAttrString(self, "__qualname__");
1326}
1327
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001328static PyObject *
1329lru_cache_copy(PyObject *self, PyObject *unused)
1330{
1331 Py_INCREF(self);
1332 return self;
1333}
1334
1335static PyObject *
1336lru_cache_deepcopy(PyObject *self, PyObject *unused)
1337{
1338 Py_INCREF(self);
1339 return self;
1340}
1341
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001342static int
1343lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1344{
Miss Islington (bot)1c0106c2021-05-28 07:26:07 -07001345 Py_VISIT(Py_TYPE(self));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001346 lru_list_elem *link = self->root.next;
1347 while (link != &self->root) {
1348 lru_list_elem *next = link->next;
INADA Naoki3070b712017-12-26 02:03:24 +09001349 Py_VISIT(link->key);
1350 Py_VISIT(link->result);
Miss Islington (bot)1c0106c2021-05-28 07:26:07 -07001351 Py_VISIT(Py_TYPE(link));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001352 link = next;
1353 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001354 Py_VISIT(self->cache);
Miss Islington (bot)1c0106c2021-05-28 07:26:07 -07001355 Py_VISIT(self->func);
Raymond Hettinger139c2322021-04-21 15:22:22 -07001356 Py_VISIT(self->kwd_mark);
1357 Py_VISIT(self->lru_list_elem_type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001358 Py_VISIT(self->cache_info_type);
1359 Py_VISIT(self->dict);
1360 return 0;
1361}
1362
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001363
1364PyDoc_STRVAR(lru_cache_doc,
1365"Create a cached callable that wraps another function.\n\
1366\n\
1367user_function: the function being cached\n\
1368\n\
1369maxsize: 0 for no caching\n\
1370 None for unlimited cache size\n\
1371 n for a bounded cache\n\
1372\n\
1373typed: False cache f(3) and f(3.0) as identical calls\n\
1374 True cache f(3) and f(3.0) as distinct calls\n\
1375\n\
1376cache_info_type: namedtuple class with the fields:\n\
1377 hits misses currsize maxsize\n"
1378);
1379
1380static PyMethodDef lru_cache_methods[] = {
1381 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1382 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001383 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001384 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1385 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001386 {NULL}
1387};
1388
1389static PyGetSetDef lru_cache_getsetlist[] = {
1390 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1391 {NULL}
1392};
1393
Hai Shidd391232020-12-29 20:45:07 +08001394static PyMemberDef lru_cache_memberlist[] = {
1395 {"__dictoffset__", T_PYSSIZET,
1396 offsetof(lru_cache_object, dict), READONLY},
1397 {"__weaklistoffset__", T_PYSSIZET,
1398 offsetof(lru_cache_object, weakreflist), READONLY},
1399 {NULL} /* Sentinel */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001400};
1401
Hai Shidd391232020-12-29 20:45:07 +08001402static PyType_Slot lru_cache_type_slots[] = {
1403 {Py_tp_dealloc, lru_cache_dealloc},
1404 {Py_tp_call, lru_cache_call},
1405 {Py_tp_doc, (void *)lru_cache_doc},
1406 {Py_tp_traverse, lru_cache_tp_traverse},
1407 {Py_tp_clear, lru_cache_tp_clear},
1408 {Py_tp_methods, lru_cache_methods},
1409 {Py_tp_members, lru_cache_memberlist},
1410 {Py_tp_getset, lru_cache_getsetlist},
1411 {Py_tp_descr_get, lru_cache_descr_get},
1412 {Py_tp_new, lru_cache_new},
1413 {0, 0}
1414};
1415
1416static PyType_Spec lru_cache_type_spec = {
1417 .name = "functools._lru_cache_wrapper",
1418 .basicsize = sizeof(lru_cache_object),
1419 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1420 Py_TPFLAGS_METHOD_DESCRIPTOR,
1421 .slots = lru_cache_type_slots
1422};
1423
1424
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001425/* module level code ********************************************************/
1426
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001427PyDoc_STRVAR(_functools_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001428"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001429
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001430static PyMethodDef _functools_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001431 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02001432 {"cmp_to_key", (PyCFunction)(void(*)(void))functools_cmp_to_key,
Victor Stinner446c8d52011-04-05 12:21:35 +02001433 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001434 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001435};
1436
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001437static int
1438_functools_exec(PyObject *module)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001439{
Hai Shidd391232020-12-29 20:45:07 +08001440 _functools_state *state = get_functools_state(module);
1441 state->kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
1442 if (state->kwd_mark == NULL) {
1443 return -1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001444 }
1445
Hai Shidd391232020-12-29 20:45:07 +08001446 state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1447 &partial_type_spec, NULL);
1448 if (state->partial_type == NULL) {
1449 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001450 }
Hai Shidd391232020-12-29 20:45:07 +08001451 if (PyModule_AddType(module, state->partial_type) < 0) {
1452 return -1;
1453 }
1454
1455 PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
1456 &lru_cache_type_spec, NULL);
1457 if (lru_cache_type == NULL) {
1458 return -1;
1459 }
1460 if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
1461 Py_DECREF(lru_cache_type);
1462 return -1;
1463 }
Victor Stinnerba0e49a2020-12-30 02:24:43 +01001464 Py_DECREF(lru_cache_type);
Hai Shidd391232020-12-29 20:45:07 +08001465
1466 state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1467 &keyobject_type_spec, NULL);
1468 if (state->keyobject_type == NULL) {
1469 return -1;
1470 }
1471 if (PyModule_AddType(module, state->keyobject_type) < 0) {
1472 return -1;
1473 }
1474
1475 state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
1476 module, &lru_list_elem_type_spec, NULL);
1477 if (state->lru_list_elem_type == NULL) {
1478 return -1;
1479 }
Miss Islington (bot)35be1f32021-05-28 00:10:45 -07001480 // lru_list_elem is used only in _lru_cache_wrapper.
1481 // So we don't expose it in module namespace.
Hai Shidd391232020-12-29 20:45:07 +08001482
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001483 return 0;
1484}
1485
Hai Shidd391232020-12-29 20:45:07 +08001486static int
1487_functools_traverse(PyObject *module, visitproc visit, void *arg)
1488{
1489 _functools_state *state = get_functools_state(module);
1490 Py_VISIT(state->kwd_mark);
1491 Py_VISIT(state->partial_type);
1492 Py_VISIT(state->keyobject_type);
1493 Py_VISIT(state->lru_list_elem_type);
1494 return 0;
1495}
1496
1497static int
1498_functools_clear(PyObject *module)
1499{
1500 _functools_state *state = get_functools_state(module);
1501 Py_CLEAR(state->kwd_mark);
1502 Py_CLEAR(state->partial_type);
1503 Py_CLEAR(state->keyobject_type);
1504 Py_CLEAR(state->lru_list_elem_type);
1505 return 0;
1506}
1507
1508static void
1509_functools_free(void *module)
1510{
1511 _functools_clear((PyObject *)module);
1512}
1513
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001514static struct PyModuleDef_Slot _functools_slots[] = {
1515 {Py_mod_exec, _functools_exec},
1516 {0, NULL}
1517};
1518
1519static struct PyModuleDef _functools_module = {
1520 PyModuleDef_HEAD_INIT,
Hai Shidd391232020-12-29 20:45:07 +08001521 .m_name = "_functools",
1522 .m_doc = _functools_doc,
1523 .m_size = sizeof(_functools_state),
1524 .m_methods = _functools_methods,
1525 .m_slots = _functools_slots,
1526 .m_traverse = _functools_traverse,
1527 .m_clear = _functools_clear,
1528 .m_free = _functools_free,
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001529};
1530
1531PyMODINIT_FUNC
1532PyInit__functools(void)
1533{
1534 return PyModuleDef_Init(&_functools_module);
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001535}