blob: fa1452168094b92e890fe8ac4ca07957ffb8e98e [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 |
Miss Islington (bot)7297d742021-06-17 03:19:44 -0700494 Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL |
495 Py_TPFLAGS_IMMUTABLETYPE,
Hai Shidd391232020-12-29 20:45:07 +0800496 .slots = partial_type_slots
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000497};
498
499
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700500/* cmp_to_key ***************************************************************/
501
502typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200503 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700504 PyObject *cmp;
505 PyObject *object;
506} keyobject;
507
Hai Shidd391232020-12-29 20:45:07 +0800508static int
509keyobject_clear(keyobject *ko)
510{
511 Py_CLEAR(ko->cmp);
512 Py_CLEAR(ko->object);
513 return 0;
514}
515
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700516static void
517keyobject_dealloc(keyobject *ko)
518{
Hai Shidd391232020-12-29 20:45:07 +0800519 PyTypeObject *tp = Py_TYPE(ko);
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700520 PyObject_GC_UnTrack(ko);
521 (void)keyobject_clear(ko);
522 tp->tp_free(ko);
Hai Shidd391232020-12-29 20:45:07 +0800523 Py_DECREF(tp);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700524}
525
526static int
527keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
528{
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700529 Py_VISIT(Py_TYPE(ko));
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700530 Py_VISIT(ko->cmp);
Hai Shi47a23fc2020-06-07 20:05:36 +0800531 Py_VISIT(ko->object);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700532 return 0;
533}
534
535static PyMemberDef keyobject_members[] = {
536 {"obj", T_OBJECT,
537 offsetof(keyobject, object), 0,
538 PyDoc_STR("Value wrapped by a key function.")},
539 {NULL}
540};
541
542static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700543keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700544
545static PyObject *
546keyobject_richcompare(PyObject *ko, PyObject *other, int op);
547
Hai Shidd391232020-12-29 20:45:07 +0800548static PyType_Slot keyobject_type_slots[] = {
549 {Py_tp_dealloc, keyobject_dealloc},
550 {Py_tp_call, keyobject_call},
551 {Py_tp_getattro, PyObject_GenericGetAttr},
552 {Py_tp_traverse, keyobject_traverse},
553 {Py_tp_clear, keyobject_clear},
554 {Py_tp_richcompare, keyobject_richcompare},
555 {Py_tp_members, keyobject_members},
556 {0, 0}
557};
558
559static PyType_Spec keyobject_type_spec = {
560 .name = "functools.KeyWrapper",
561 .basicsize = sizeof(keyobject),
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700562 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
Miss Islington (bot)7297d742021-06-17 03:19:44 -0700563 Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
Hai Shidd391232020-12-29 20:45:07 +0800564 .slots = keyobject_type_slots
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700565};
566
567static PyObject *
568keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
569{
570 PyObject *object;
571 keyobject *result;
572 static char *kwargs[] = {"obj", NULL};
573
574 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
575 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800576
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700577 result = PyObject_GC_New(keyobject, Py_TYPE(ko));
Hai Shidd391232020-12-29 20:45:07 +0800578 if (result == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700579 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800580 }
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700581 Py_INCREF(ko->cmp);
582 result->cmp = ko->cmp;
583 Py_INCREF(object);
584 result->object = object;
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700585 PyObject_GC_Track(result);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700586 return (PyObject *)result;
587}
588
589static PyObject *
590keyobject_richcompare(PyObject *ko, PyObject *other, int op)
591{
592 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700593 PyObject *x;
594 PyObject *y;
595 PyObject *compare;
596 PyObject *answer;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200597 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700598
Hai Shidd391232020-12-29 20:45:07 +0800599 if (!Py_IS_TYPE(other, Py_TYPE(ko))) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700600 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
601 return NULL;
602 }
603 compare = ((keyobject *) ko)->cmp;
604 assert(compare != NULL);
605 x = ((keyobject *) ko)->object;
606 y = ((keyobject *) other)->object;
607 if (!x || !y){
608 PyErr_Format(PyExc_AttributeError, "object");
609 return NULL;
610 }
611
612 /* Call the user's comparison function and translate the 3-way
613 * result into true or false (or error).
614 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200615 stack[0] = x;
616 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200617 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200618 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700619 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200620 }
621
Victor Stinner37834132020-10-27 17:12:53 +0100622 answer = PyObject_RichCompare(res, _PyLong_GetZero(), op);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700623 Py_DECREF(res);
624 return answer;
625}
626
627static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200628functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
629{
630 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700631 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200632 keyobject *object;
Hai Shidd391232020-12-29 20:45:07 +0800633 _functools_state *state;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700634
635 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
636 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800637
638 state = get_functools_state(self);
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700639 object = PyObject_GC_New(keyobject, state->keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700640 if (!object)
641 return NULL;
642 Py_INCREF(cmp);
643 object->cmp = cmp;
644 object->object = NULL;
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700645 PyObject_GC_Track(object);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700646 return (PyObject *)object;
647}
648
649PyDoc_STRVAR(functools_cmp_to_key_doc,
650"Convert a cmp= function into a key= function.");
651
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000652/* reduce (used to be a builtin) ********************************************/
653
654static PyObject *
655functools_reduce(PyObject *self, PyObject *args)
656{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000657 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000658
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000659 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
660 return NULL;
661 if (result != NULL)
662 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000663
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000664 it = PyObject_GetIter(seq);
665 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000666 if (PyErr_ExceptionMatches(PyExc_TypeError))
667 PyErr_SetString(PyExc_TypeError,
668 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000669 Py_XDECREF(result);
670 return NULL;
671 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000672
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000673 if ((args = PyTuple_New(2)) == NULL)
674 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000675
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000676 for (;;) {
677 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000678
Victor Stinnera93c51e2020-02-07 00:38:59 +0100679 if (Py_REFCNT(args) > 1) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000680 Py_DECREF(args);
681 if ((args = PyTuple_New(2)) == NULL)
682 goto Fail;
683 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000684
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000685 op2 = PyIter_Next(it);
686 if (op2 == NULL) {
687 if (PyErr_Occurred())
688 goto Fail;
689 break;
690 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000691
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000692 if (result == NULL)
693 result = op2;
694 else {
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500695 /* Update the args tuple in-place */
Victor Stinnera93c51e2020-02-07 00:38:59 +0100696 assert(Py_REFCNT(args) == 1);
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500697 Py_XSETREF(_PyTuple_ITEMS(args)[0], result);
698 Py_XSETREF(_PyTuple_ITEMS(args)[1], op2);
699 if ((result = PyObject_Call(func, args, NULL)) == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000700 goto Fail;
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500701 }
Brandt Bucher226a0122020-12-04 19:45:57 -0800702 // bpo-42536: The GC may have untracked this args tuple. Since we're
703 // recycling it, make sure it's tracked again:
704 if (!_PyObject_GC_IS_TRACKED(args)) {
705 _PyObject_GC_TRACK(args);
706 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000707 }
708 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000709
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000710 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000711
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000712 if (result == NULL)
713 PyErr_SetString(PyExc_TypeError,
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600714 "reduce() of empty iterable with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000715
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000716 Py_DECREF(it);
717 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000718
719Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000720 Py_XDECREF(args);
721 Py_XDECREF(result);
722 Py_DECREF(it);
723 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000724}
725
726PyDoc_STRVAR(functools_reduce_doc,
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600727"reduce(function, iterable[, initial]) -> value\n\
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000728\n\
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600729Apply a function of two arguments cumulatively to the items of a sequence\n\
730or iterable, from left to right, so as to reduce the iterable to a single\n\
731value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000732((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600733of the iterable in the calculation, and serves as a default when the\n\
734iterable is empty.");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000735
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300736/* lru_cache object **********************************************************/
737
Raymond Hettinger2dda72a2019-02-08 18:55:02 -0800738/* There are four principal algorithmic differences from the pure python version:
739
740 1). The C version relies on the GIL instead of having its own reentrant lock.
741
742 2). The prev/next link fields use borrowed references.
743
744 3). For a full cache, the pure python version rotates the location of the
745 root entry so that it never has to move individual links and it can
746 limit updates to just the key and result fields. However, in the C
747 version, links are temporarily removed while the cache dict updates are
748 occurring. Afterwards, they are appended or prepended back into the
749 doubly-linked lists.
750
751 4) In the Python version, the _HashSeq class is used to prevent __hash__
752 from being called more than once. In the C version, the "known hash"
753 variants of dictionary calls as used to the same effect.
754
755*/
756
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300757struct lru_list_elem;
758struct lru_cache_object;
759
760typedef struct lru_list_elem {
761 PyObject_HEAD
762 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300763 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300764 PyObject *key, *result;
765} lru_list_elem;
766
767static void
768lru_list_elem_dealloc(lru_list_elem *link)
769{
Hai Shidd391232020-12-29 20:45:07 +0800770 PyTypeObject *tp = Py_TYPE(link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300771 Py_XDECREF(link->key);
772 Py_XDECREF(link->result);
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -0700773 tp->tp_free(link);
Hai Shidd391232020-12-29 20:45:07 +0800774 Py_DECREF(tp);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300775}
776
Hai Shidd391232020-12-29 20:45:07 +0800777static PyType_Slot lru_list_elem_type_slots[] = {
778 {Py_tp_dealloc, lru_list_elem_dealloc},
779 {0, 0}
780};
781
782static PyType_Spec lru_list_elem_type_spec = {
783 .name = "functools._lru_list_elem",
784 .basicsize = sizeof(lru_list_elem),
Miss Islington (bot)7297d742021-06-17 03:19:44 -0700785 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
786 Py_TPFLAGS_IMMUTABLETYPE,
Hai Shidd391232020-12-29 20:45:07 +0800787 .slots = lru_list_elem_type_slots
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300788};
789
790
791typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
792
793typedef struct lru_cache_object {
794 lru_list_elem root; /* includes PyObject_HEAD */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300795 lru_cache_ternaryfunc wrapper;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300796 int typed;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500797 PyObject *cache;
798 Py_ssize_t hits;
799 PyObject *func;
800 Py_ssize_t maxsize;
801 Py_ssize_t misses;
Raymond Hettinger139c2322021-04-21 15:22:22 -0700802 /* the kwd_mark is used delimit args and keywords in the cache keys */
803 PyObject *kwd_mark;
804 PyTypeObject *lru_list_elem_type;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500805 PyObject *cache_info_type;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300806 PyObject *dict;
Dennis Sweeney1253c3e2020-05-05 17:14:32 -0400807 PyObject *weakreflist;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300808} lru_cache_object;
809
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300810static PyObject *
Raymond Hettinger139c2322021-04-21 15:22:22 -0700811lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
Hai Shidd391232020-12-29 20:45:07 +0800812 PyObject *kwds, int typed)
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300813{
Raymond Hettingerdda44682017-01-08 18:04:30 -0800814 PyObject *key, *keyword, *value;
815 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300816
Raymond Hettinger14adbd42019-04-20 07:20:44 -1000817 kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
818
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300819 /* short path, key will match args anyway, which is a tuple */
Raymond Hettinger14adbd42019-04-20 07:20:44 -1000820 if (!typed && !kwds_size) {
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500821 if (PyTuple_GET_SIZE(args) == 1) {
822 key = PyTuple_GET_ITEM(args, 0);
823 if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) {
824 /* For common scalar keys, save space by
825 dropping the enclosing args tuple */
826 Py_INCREF(key);
827 return key;
828 }
829 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300830 Py_INCREF(args);
831 return args;
832 }
833
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300834 key_size = PyTuple_GET_SIZE(args);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800835 if (kwds_size)
836 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300837 if (typed)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800838 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300839
840 key = PyTuple_New(key_size);
841 if (key == NULL)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800842 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300843
844 key_pos = 0;
845 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
846 PyObject *item = PyTuple_GET_ITEM(args, pos);
847 Py_INCREF(item);
848 PyTuple_SET_ITEM(key, key_pos++, item);
849 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800850 if (kwds_size) {
Raymond Hettinger139c2322021-04-21 15:22:22 -0700851 Py_INCREF(kwd_mark);
852 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800853 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
854 Py_INCREF(keyword);
855 PyTuple_SET_ITEM(key, key_pos++, keyword);
856 Py_INCREF(value);
857 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300858 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800859 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300860 }
861 if (typed) {
862 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
863 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
864 Py_INCREF(item);
865 PyTuple_SET_ITEM(key, key_pos++, item);
866 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800867 if (kwds_size) {
868 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
869 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300870 Py_INCREF(item);
871 PyTuple_SET_ITEM(key, key_pos++, item);
872 }
873 }
874 }
875 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300876 return key;
877}
878
879static PyObject *
880uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
881{
Raymond Hettingerffdf1c32019-01-31 15:03:38 -0800882 PyObject *result;
883
884 self->misses++;
885 result = PyObject_Call(self->func, args, kwds);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300886 if (!result)
887 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300888 return result;
889}
890
891static PyObject *
892infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
893{
894 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300895 Py_hash_t hash;
Raymond Hettinger139c2322021-04-21 15:22:22 -0700896 PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300897 if (!key)
898 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300899 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500900 if (hash == -1) {
901 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300902 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500903 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300904 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300905 if (result) {
906 Py_INCREF(result);
907 self->hits++;
908 Py_DECREF(key);
909 return result;
910 }
911 if (PyErr_Occurred()) {
912 Py_DECREF(key);
913 return NULL;
914 }
Raymond Hettingerffdf1c32019-01-31 15:03:38 -0800915 self->misses++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300916 result = PyObject_Call(self->func, args, kwds);
917 if (!result) {
918 Py_DECREF(key);
919 return NULL;
920 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300921 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300922 Py_DECREF(result);
923 Py_DECREF(key);
924 return NULL;
925 }
926 Py_DECREF(key);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300927 return result;
928}
929
930static void
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500931lru_cache_extract_link(lru_list_elem *link)
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300932{
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500933 lru_list_elem *link_prev = link->prev;
934 lru_list_elem *link_next = link->next;
935 link_prev->next = link->next;
936 link_next->prev = link->prev;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300937}
938
939static void
940lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
941{
942 lru_list_elem *root = &self->root;
943 lru_list_elem *last = root->prev;
944 last->next = root->prev = link;
945 link->prev = last;
946 link->next = root;
947}
948
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500949static void
950lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
951{
952 lru_list_elem *root = &self->root;
953 lru_list_elem *first = root->next;
954 first->prev = root->next = link;
955 link->prev = root;
956 link->next = first;
957}
958
959/* General note on reentrancy:
960
961 There are four dictionary calls in the bounded_lru_cache_wrapper():
962 1) The initial check for a cache match. 2) The post user-function
963 check for a cache match. 3) The deletion of the oldest entry.
964 4) The addition of the newest entry.
965
966 In all four calls, we have a known hash which lets use avoid a call
967 to __hash__(). That leaves only __eq__ as a possible source of a
968 reentrant call.
969
970 The __eq__ method call is always made for a cache hit (dict access #1).
971 Accordingly, we have make sure not modify the cache state prior to
972 this call.
973
974 The __eq__ method call is never made for the deletion (dict access #3)
975 because it is an identity match.
976
977 For the other two accesses (#2 and #4), calls to __eq__ only occur
978 when some other entry happens to have an exactly matching hash (all
979 64-bits). Though rare, this can happen, so we have to make sure to
980 either call it at the top of its code path before any cache
981 state modifications (dict access #2) or be prepared to restore
982 invariants at the end of the code path (dict access #4).
983
984 Another possible source of reentrancy is a decref which can trigger
985 arbitrary code execution. To make the code easier to reason about,
986 the decrefs are deferred to the end of the each possible code path
987 so that we know the cache is a consistent state.
988 */
989
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300990static PyObject *
991bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
992{
993 lru_list_elem *link;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500994 PyObject *key, *result, *testresult;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300995 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300996
Raymond Hettinger139c2322021-04-21 15:22:22 -0700997 key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300998 if (!key)
999 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001000 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -05001001 if (hash == -1) {
1002 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001003 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -05001004 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001005 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001006 if (link != NULL) {
1007 lru_cache_extract_link(link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001008 lru_cache_append_link(self, link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001009 result = link->result;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001010 self->hits++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001011 Py_INCREF(result);
1012 Py_DECREF(key);
1013 return result;
1014 }
1015 if (PyErr_Occurred()) {
1016 Py_DECREF(key);
1017 return NULL;
1018 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001019 self->misses++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001020 result = PyObject_Call(self->func, args, kwds);
1021 if (!result) {
1022 Py_DECREF(key);
1023 return NULL;
1024 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001025 testresult = _PyDict_GetItem_KnownHash(self->cache, key, hash);
1026 if (testresult != NULL) {
1027 /* Getting here means that this same key was added to the cache
1028 during the PyObject_Call(). Since the link update is already
1029 done, we need only return the computed result. */
1030 Py_DECREF(key);
1031 return result;
1032 }
1033 if (PyErr_Occurred()) {
1034 /* This is an unusual case since this same lookup
1035 did not previously trigger an error during lookup.
1036 Treat it the same as an error in user function
1037 and return with the error set. */
1038 Py_DECREF(key);
1039 Py_DECREF(result);
1040 return NULL;
1041 }
1042 /* This is the normal case. The new key wasn't found before
1043 user function call and it is still not there. So we
1044 proceed normally and update the cache with the new result. */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001045
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001046 assert(self->maxsize > 0);
1047 if (PyDict_GET_SIZE(self->cache) < self->maxsize ||
1048 self->root.next == &self->root)
1049 {
1050 /* Cache is not full, so put the result in a new link */
INADA Naoki3070b712017-12-26 02:03:24 +09001051 link = (lru_list_elem *)PyObject_New(lru_list_elem,
Raymond Hettinger139c2322021-04-21 15:22:22 -07001052 self->lru_list_elem_type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001053 if (link == NULL) {
1054 Py_DECREF(key);
1055 Py_DECREF(result);
1056 return NULL;
1057 }
1058
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001059 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001060 link->key = key;
1061 link->result = result;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001062 /* What is really needed here is a SetItem variant with a "no clobber"
1063 option. If the __eq__ call triggers a reentrant call that adds
1064 this same key, then this setitem call will update the cache dict
1065 with this new link, leaving the old link as an orphan (i.e. not
1066 having a cache dict entry that refers to it). */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001067 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
1068 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001069 Py_DECREF(link);
1070 return NULL;
1071 }
1072 lru_cache_append_link(self, link);
1073 Py_INCREF(result); /* for return */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001074 return result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001075 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001076 /* Since the cache is full, we need to evict an old key and add
1077 a new key. Rather than free the old link and allocate a new
1078 one, we reuse the link for the new key and result and move it
1079 to front of the cache to mark it as recently used.
1080
1081 We try to assure all code paths (including errors) leave all
1082 of the links in place. Either the link is successfully
1083 updated and moved or it is restored to its old position.
1084 However if an unrecoverable error is found, it doesn't
1085 make sense to reinsert the link, so we leave it out
1086 and the cache will no longer register as full.
1087 */
1088 PyObject *oldkey, *oldresult, *popresult;
1089
1090 /* Extract the oldest item. */
1091 assert(self->root.next != &self->root);
1092 link = self->root.next;
1093 lru_cache_extract_link(link);
1094 /* Remove it from the cache.
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001095 The cache dict holds one reference to the link.
1096 We created one other reference when the link was created.
1097 The linked list only has borrowed references. */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001098 popresult = _PyDict_Pop_KnownHash(self->cache, link->key,
1099 link->hash, Py_None);
1100 if (popresult == Py_None) {
1101 /* Getting here means that the user function call or another
1102 thread has already removed the old key from the dictionary.
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001103 This link is now an orphan. Since we don't want to leave the
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001104 cache in an inconsistent state, we don't restore the link. */
1105 Py_DECREF(popresult);
1106 Py_DECREF(link);
1107 Py_DECREF(key);
1108 return result;
1109 }
1110 if (popresult == NULL) {
1111 /* An error arose while trying to remove the oldest key (the one
1112 being evicted) from the cache. We restore the link to its
1113 original position as the oldest link. Then we allow the
1114 error propagate upward; treating it the same as an error
1115 arising in the user function. */
1116 lru_cache_prepend_link(self, link);
1117 Py_DECREF(key);
1118 Py_DECREF(result);
1119 return NULL;
1120 }
1121 /* Keep a reference to the old key and old result to prevent their
1122 ref counts from going to zero during the update. That will
1123 prevent potentially arbitrary object clean-up code (i.e. __del__)
1124 from running while we're still adjusting the links. */
1125 oldkey = link->key;
1126 oldresult = link->result;
1127
1128 link->hash = hash;
1129 link->key = key;
1130 link->result = result;
1131 /* Note: The link is being added to the cache dict without the
1132 prev and next fields set to valid values. We have to wait
1133 for successful insertion in the cache dict before adding the
1134 link to the linked list. Otherwise, the potentially reentrant
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001135 __eq__ call could cause the then orphan link to be visited. */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001136 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
1137 hash) < 0) {
1138 /* Somehow the cache dict update failed. We no longer can
1139 restore the old link. Let the error propagate upward and
1140 leave the cache short one link. */
1141 Py_DECREF(popresult);
1142 Py_DECREF(link);
1143 Py_DECREF(oldkey);
1144 Py_DECREF(oldresult);
1145 return NULL;
1146 }
1147 lru_cache_append_link(self, link);
1148 Py_INCREF(result); /* for return */
1149 Py_DECREF(popresult);
1150 Py_DECREF(oldkey);
1151 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001152 return result;
1153}
1154
1155static PyObject *
1156lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
1157{
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001158 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001159 int typed;
1160 lru_cache_object *obj;
1161 Py_ssize_t maxsize;
1162 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
Raymond Hettinger139c2322021-04-21 15:22:22 -07001163 _functools_state *state;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001164 static char *keywords[] = {"user_function", "maxsize", "typed",
1165 "cache_info_type", NULL};
1166
1167 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
1168 &func, &maxsize_O, &typed,
1169 &cache_info_type)) {
1170 return NULL;
1171 }
1172
1173 if (!PyCallable_Check(func)) {
1174 PyErr_SetString(PyExc_TypeError,
1175 "the first argument must be callable");
1176 return NULL;
1177 }
1178
Raymond Hettinger139c2322021-04-21 15:22:22 -07001179 state = get_functools_state_by_type(type);
1180 if (state == NULL) {
1181 return NULL;
1182 }
1183
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001184 /* select the caching function, and make/inc maxsize_O */
1185 if (maxsize_O == Py_None) {
1186 wrapper = infinite_lru_cache_wrapper;
1187 /* use this only to initialize lru_cache_object attribute maxsize */
1188 maxsize = -1;
1189 } else if (PyIndex_Check(maxsize_O)) {
1190 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1191 if (maxsize == -1 && PyErr_Occurred())
1192 return NULL;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001193 if (maxsize < 0) {
1194 maxsize = 0;
1195 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001196 if (maxsize == 0)
1197 wrapper = uncached_lru_cache_wrapper;
1198 else
1199 wrapper = bounded_lru_cache_wrapper;
1200 } else {
1201 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1202 return NULL;
1203 }
1204
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001205 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001206 return NULL;
1207
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001208 obj = (lru_cache_object *)type->tp_alloc(type, 0);
1209 if (obj == NULL) {
1210 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001211 return NULL;
1212 }
1213
1214 obj->root.prev = &obj->root;
1215 obj->root.next = &obj->root;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001216 obj->wrapper = wrapper;
1217 obj->typed = typed;
1218 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001219 Py_INCREF(func);
1220 obj->func = func;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001221 obj->misses = obj->hits = 0;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001222 obj->maxsize = maxsize;
Raymond Hettinger139c2322021-04-21 15:22:22 -07001223 Py_INCREF(state->kwd_mark);
1224 obj->kwd_mark = state->kwd_mark;
1225 Py_INCREF(state->lru_list_elem_type);
1226 obj->lru_list_elem_type = state->lru_list_elem_type;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001227 Py_INCREF(cache_info_type);
1228 obj->cache_info_type = cache_info_type;
Raymond Hettingerbba760e2020-04-20 13:47:12 -07001229 obj->dict = NULL;
Dennis Sweeney1253c3e2020-05-05 17:14:32 -04001230 obj->weakreflist = NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001231 return (PyObject *)obj;
1232}
1233
1234static lru_list_elem *
1235lru_cache_unlink_list(lru_cache_object *self)
1236{
1237 lru_list_elem *root = &self->root;
1238 lru_list_elem *link = root->next;
1239 if (link == root)
1240 return NULL;
1241 root->prev->next = NULL;
1242 root->next = root->prev = root;
1243 return link;
1244}
1245
1246static void
1247lru_cache_clear_list(lru_list_elem *link)
1248{
1249 while (link != NULL) {
1250 lru_list_elem *next = link->next;
1251 Py_DECREF(link);
1252 link = next;
1253 }
1254}
1255
Hai Shidd391232020-12-29 20:45:07 +08001256static int
1257lru_cache_tp_clear(lru_cache_object *self)
1258{
1259 lru_list_elem *list = lru_cache_unlink_list(self);
Hai Shidd391232020-12-29 20:45:07 +08001260 Py_CLEAR(self->cache);
Miss Islington (bot)1c0106c2021-05-28 07:26:07 -07001261 Py_CLEAR(self->func);
Raymond Hettinger139c2322021-04-21 15:22:22 -07001262 Py_CLEAR(self->kwd_mark);
1263 Py_CLEAR(self->lru_list_elem_type);
Hai Shidd391232020-12-29 20:45:07 +08001264 Py_CLEAR(self->cache_info_type);
1265 Py_CLEAR(self->dict);
1266 lru_cache_clear_list(list);
1267 return 0;
1268}
1269
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001270static void
1271lru_cache_dealloc(lru_cache_object *obj)
1272{
Hai Shidd391232020-12-29 20:45:07 +08001273 PyTypeObject *tp = Py_TYPE(obj);
INADA Naokia6296d32017-08-24 14:55:17 +09001274 /* bpo-31095: UnTrack is needed before calling any callbacks */
1275 PyObject_GC_UnTrack(obj);
Hai Shidd391232020-12-29 20:45:07 +08001276 if (obj->weakreflist != NULL) {
Dennis Sweeney1253c3e2020-05-05 17:14:32 -04001277 PyObject_ClearWeakRefs((PyObject*)obj);
Hai Shidd391232020-12-29 20:45:07 +08001278 }
INADA Naokia6296d32017-08-24 14:55:17 +09001279
Miss Islington (bot)eb8ab042021-05-28 02:08:01 -07001280 (void)lru_cache_tp_clear(obj);
Hai Shidd391232020-12-29 20:45:07 +08001281 tp->tp_free(obj);
1282 Py_DECREF(tp);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001283}
1284
1285static PyObject *
1286lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1287{
1288 return self->wrapper(self, args, kwds);
1289}
1290
1291static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001292lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1293{
1294 if (obj == Py_None || obj == NULL) {
1295 Py_INCREF(self);
1296 return self;
1297 }
1298 return PyMethod_New(self, obj);
1299}
1300
1301static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001302lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1303{
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001304 if (self->maxsize == -1) {
1305 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1306 self->hits, self->misses, Py_None,
1307 PyDict_GET_SIZE(self->cache));
1308 }
1309 return PyObject_CallFunction(self->cache_info_type, "nnnn",
1310 self->hits, self->misses, self->maxsize,
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +02001311 PyDict_GET_SIZE(self->cache));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001312}
1313
1314static PyObject *
1315lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1316{
1317 lru_list_elem *list = lru_cache_unlink_list(self);
1318 self->hits = self->misses = 0;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001319 PyDict_Clear(self->cache);
1320 lru_cache_clear_list(list);
1321 Py_RETURN_NONE;
1322}
1323
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001324static PyObject *
1325lru_cache_reduce(PyObject *self, PyObject *unused)
1326{
1327 return PyObject_GetAttrString(self, "__qualname__");
1328}
1329
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001330static PyObject *
1331lru_cache_copy(PyObject *self, PyObject *unused)
1332{
1333 Py_INCREF(self);
1334 return self;
1335}
1336
1337static PyObject *
1338lru_cache_deepcopy(PyObject *self, PyObject *unused)
1339{
1340 Py_INCREF(self);
1341 return self;
1342}
1343
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001344static int
1345lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1346{
Miss Islington (bot)1c0106c2021-05-28 07:26:07 -07001347 Py_VISIT(Py_TYPE(self));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001348 lru_list_elem *link = self->root.next;
1349 while (link != &self->root) {
1350 lru_list_elem *next = link->next;
INADA Naoki3070b712017-12-26 02:03:24 +09001351 Py_VISIT(link->key);
1352 Py_VISIT(link->result);
Miss Islington (bot)1c0106c2021-05-28 07:26:07 -07001353 Py_VISIT(Py_TYPE(link));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001354 link = next;
1355 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001356 Py_VISIT(self->cache);
Miss Islington (bot)1c0106c2021-05-28 07:26:07 -07001357 Py_VISIT(self->func);
Raymond Hettinger139c2322021-04-21 15:22:22 -07001358 Py_VISIT(self->kwd_mark);
1359 Py_VISIT(self->lru_list_elem_type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001360 Py_VISIT(self->cache_info_type);
1361 Py_VISIT(self->dict);
1362 return 0;
1363}
1364
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001365
1366PyDoc_STRVAR(lru_cache_doc,
1367"Create a cached callable that wraps another function.\n\
1368\n\
1369user_function: the function being cached\n\
1370\n\
1371maxsize: 0 for no caching\n\
1372 None for unlimited cache size\n\
1373 n for a bounded cache\n\
1374\n\
1375typed: False cache f(3) and f(3.0) as identical calls\n\
1376 True cache f(3) and f(3.0) as distinct calls\n\
1377\n\
1378cache_info_type: namedtuple class with the fields:\n\
1379 hits misses currsize maxsize\n"
1380);
1381
1382static PyMethodDef lru_cache_methods[] = {
1383 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1384 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001385 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001386 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1387 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001388 {NULL}
1389};
1390
1391static PyGetSetDef lru_cache_getsetlist[] = {
1392 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1393 {NULL}
1394};
1395
Hai Shidd391232020-12-29 20:45:07 +08001396static PyMemberDef lru_cache_memberlist[] = {
1397 {"__dictoffset__", T_PYSSIZET,
1398 offsetof(lru_cache_object, dict), READONLY},
1399 {"__weaklistoffset__", T_PYSSIZET,
1400 offsetof(lru_cache_object, weakreflist), READONLY},
1401 {NULL} /* Sentinel */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001402};
1403
Hai Shidd391232020-12-29 20:45:07 +08001404static PyType_Slot lru_cache_type_slots[] = {
1405 {Py_tp_dealloc, lru_cache_dealloc},
1406 {Py_tp_call, lru_cache_call},
1407 {Py_tp_doc, (void *)lru_cache_doc},
1408 {Py_tp_traverse, lru_cache_tp_traverse},
1409 {Py_tp_clear, lru_cache_tp_clear},
1410 {Py_tp_methods, lru_cache_methods},
1411 {Py_tp_members, lru_cache_memberlist},
1412 {Py_tp_getset, lru_cache_getsetlist},
1413 {Py_tp_descr_get, lru_cache_descr_get},
1414 {Py_tp_new, lru_cache_new},
1415 {0, 0}
1416};
1417
1418static PyType_Spec lru_cache_type_spec = {
1419 .name = "functools._lru_cache_wrapper",
1420 .basicsize = sizeof(lru_cache_object),
1421 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Miss Islington (bot)7297d742021-06-17 03:19:44 -07001422 Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_IMMUTABLETYPE,
Hai Shidd391232020-12-29 20:45:07 +08001423 .slots = lru_cache_type_slots
1424};
1425
1426
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001427/* module level code ********************************************************/
1428
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001429PyDoc_STRVAR(_functools_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001430"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001431
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001432static PyMethodDef _functools_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001433 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02001434 {"cmp_to_key", (PyCFunction)(void(*)(void))functools_cmp_to_key,
Victor Stinner446c8d52011-04-05 12:21:35 +02001435 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001436 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001437};
1438
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001439static int
1440_functools_exec(PyObject *module)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001441{
Hai Shidd391232020-12-29 20:45:07 +08001442 _functools_state *state = get_functools_state(module);
1443 state->kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
1444 if (state->kwd_mark == NULL) {
1445 return -1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001446 }
1447
Hai Shidd391232020-12-29 20:45:07 +08001448 state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1449 &partial_type_spec, NULL);
1450 if (state->partial_type == NULL) {
1451 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001452 }
Hai Shidd391232020-12-29 20:45:07 +08001453 if (PyModule_AddType(module, state->partial_type) < 0) {
1454 return -1;
1455 }
1456
1457 PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
1458 &lru_cache_type_spec, NULL);
1459 if (lru_cache_type == NULL) {
1460 return -1;
1461 }
1462 if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
1463 Py_DECREF(lru_cache_type);
1464 return -1;
1465 }
Victor Stinnerba0e49a2020-12-30 02:24:43 +01001466 Py_DECREF(lru_cache_type);
Hai Shidd391232020-12-29 20:45:07 +08001467
1468 state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1469 &keyobject_type_spec, NULL);
1470 if (state->keyobject_type == NULL) {
1471 return -1;
1472 }
1473 if (PyModule_AddType(module, state->keyobject_type) < 0) {
1474 return -1;
1475 }
1476
1477 state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
1478 module, &lru_list_elem_type_spec, NULL);
1479 if (state->lru_list_elem_type == NULL) {
1480 return -1;
1481 }
Miss Islington (bot)35be1f32021-05-28 00:10:45 -07001482 // lru_list_elem is used only in _lru_cache_wrapper.
1483 // So we don't expose it in module namespace.
Hai Shidd391232020-12-29 20:45:07 +08001484
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001485 return 0;
1486}
1487
Hai Shidd391232020-12-29 20:45:07 +08001488static int
1489_functools_traverse(PyObject *module, visitproc visit, void *arg)
1490{
1491 _functools_state *state = get_functools_state(module);
1492 Py_VISIT(state->kwd_mark);
1493 Py_VISIT(state->partial_type);
1494 Py_VISIT(state->keyobject_type);
1495 Py_VISIT(state->lru_list_elem_type);
1496 return 0;
1497}
1498
1499static int
1500_functools_clear(PyObject *module)
1501{
1502 _functools_state *state = get_functools_state(module);
1503 Py_CLEAR(state->kwd_mark);
1504 Py_CLEAR(state->partial_type);
1505 Py_CLEAR(state->keyobject_type);
1506 Py_CLEAR(state->lru_list_elem_type);
1507 return 0;
1508}
1509
1510static void
1511_functools_free(void *module)
1512{
1513 _functools_clear((PyObject *)module);
1514}
1515
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001516static struct PyModuleDef_Slot _functools_slots[] = {
1517 {Py_mod_exec, _functools_exec},
1518 {0, NULL}
1519};
1520
1521static struct PyModuleDef _functools_module = {
1522 PyModuleDef_HEAD_INIT,
Hai Shidd391232020-12-29 20:45:07 +08001523 .m_name = "_functools",
1524 .m_doc = _functools_doc,
1525 .m_size = sizeof(_functools_state),
1526 .m_methods = _functools_methods,
1527 .m_slots = _functools_slots,
1528 .m_traverse = _functools_traverse,
1529 .m_clear = _functools_clear,
1530 .m_free = _functools_free,
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001531};
1532
1533PyMODINIT_FUNC
1534PyInit__functools(void)
1535{
1536 return PyModuleDef_Init(&_functools_module);
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001537}