blob: 1fcaf299e67bc6950e7a263d4eaca78afcdde20e [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()
Brandt Bucher226a0122020-12-04 19:45:57 -08003#include "pycore_object.h" // _PyObject_GC_TRACK
Victor Stinner4a21e572020-04-15 02:35:41 +02004#include "pycore_pystate.h" // _PyThreadState_GET()
Victor Stinner384621c2020-06-22 17:27:35 +02005#include "pycore_tuple.h" // _PyTuple_ITEMS()
Victor Stinner4a21e572020-04-15 02:35:41 +02006#include "structmember.h" // PyMemberDef
Raymond Hettinger9c323f82005-02-28 19:39:44 +00007
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00008/* _functools module written and maintained
Raymond Hettinger9c323f82005-02-28 19:39:44 +00009 by Hye-Shik Chang <perky@FreeBSD.org>
10 with adaptations by Raymond Hettinger <python@rcn.com>
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000011 Copyright (c) 2004, 2005, 2006 Python Software Foundation.
Raymond Hettinger9c323f82005-02-28 19:39:44 +000012 All rights reserved.
13*/
14
15/* partial object **********************************************************/
16
17typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000018 PyObject_HEAD
19 PyObject *fn;
20 PyObject *args;
21 PyObject *kw;
Jeroen Demeyered184c02019-07-13 16:39:18 +020022 PyObject *dict; /* __dict__ */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000023 PyObject *weakreflist; /* List of weak references */
Jeroen Demeyered184c02019-07-13 16:39:18 +020024 vectorcallfunc vectorcall;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000025} partialobject;
26
Hai Shidd391232020-12-29 20:45:07 +080027typedef struct _functools_state {
28 /* this object is used delimit args and keywords in the cache keys */
29 PyObject *kwd_mark;
30 PyTypeObject *partial_type;
31 PyTypeObject *keyobject_type;
32 PyTypeObject *lru_list_elem_type;
33} _functools_state;
34
35static inline _functools_state *
36get_functools_state(PyObject *module)
37{
38 void *state = PyModule_GetState(module);
39 assert(state != NULL);
40 return (_functools_state *)state;
41}
Raymond Hettinger9c323f82005-02-28 19:39:44 +000042
Jeroen Demeyered184c02019-07-13 16:39:18 +020043static void partial_setvectorcall(partialobject *pto);
Hai Shidd391232020-12-29 20:45:07 +080044static struct PyModuleDef _functools_module;
45static PyObject *
46partial_call(partialobject *pto, PyObject *args, PyObject *kwargs);
47
48static inline _functools_state *
49get_functools_state_by_type(PyTypeObject *type)
50{
51 PyObject *module = _PyType_GetModuleByDef(type, &_functools_module);
52 if (module == NULL) {
53 return NULL;
54 }
55 _functools_state *state = get_functools_state(module);
56 return state;
57}
Jeroen Demeyered184c02019-07-13 16:39:18 +020058
Raymond Hettinger9c323f82005-02-28 19:39:44 +000059static PyObject *
60partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
61{
Alexander Belopolskye49af342015-03-01 15:08:17 -050062 PyObject *func, *pargs, *nargs, *pkw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000063 partialobject *pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000064
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000065 if (PyTuple_GET_SIZE(args) < 1) {
66 PyErr_SetString(PyExc_TypeError,
67 "type 'partial' takes at least one argument");
68 return NULL;
69 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000070
Serhiy Storchaka38741282016-02-02 18:45:17 +020071 pargs = pkw = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000072 func = PyTuple_GET_ITEM(args, 0);
Hai Shidd391232020-12-29 20:45:07 +080073 if (Py_TYPE(func)->tp_call == (ternaryfunc)partial_call) {
74 // The type of "func" might not be exactly the same type object
75 // as "type", but if it is called using partial_call, it must have the
76 // same memory layout (fn, args and kw members).
77 // We can use its underlying function directly and merge the arguments.
Alexander Belopolskye49af342015-03-01 15:08:17 -050078 partialobject *part = (partialobject *)func;
79 if (part->dict == NULL) {
80 pargs = part->args;
81 pkw = part->kw;
82 func = part->fn;
Serhiy Storchaka38741282016-02-02 18:45:17 +020083 assert(PyTuple_Check(pargs));
84 assert(PyDict_Check(pkw));
Alexander Belopolskye49af342015-03-01 15:08:17 -050085 }
86 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000087 if (!PyCallable_Check(func)) {
88 PyErr_SetString(PyExc_TypeError,
89 "the first argument must be callable");
90 return NULL;
91 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000092
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000093 /* create partialobject structure */
94 pto = (partialobject *)type->tp_alloc(type, 0);
95 if (pto == NULL)
96 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000097
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000098 pto->fn = func;
99 Py_INCREF(func);
Alexander Belopolskye49af342015-03-01 15:08:17 -0500100
101 nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
102 if (nargs == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000103 Py_DECREF(pto);
104 return NULL;
105 }
Serhiy Storchaka3c749fc2017-03-25 12:10:16 +0200106 if (pargs == NULL) {
Alexander Belopolskye49af342015-03-01 15:08:17 -0500107 pto->args = nargs;
Alexander Belopolskye49af342015-03-01 15:08:17 -0500108 }
109 else {
110 pto->args = PySequence_Concat(pargs, nargs);
Serhiy Storchaka3c749fc2017-03-25 12:10:16 +0200111 Py_DECREF(nargs);
Alexander Belopolskye49af342015-03-01 15:08:17 -0500112 if (pto->args == NULL) {
Alexander Belopolskye49af342015-03-01 15:08:17 -0500113 Py_DECREF(pto);
114 return NULL;
115 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200116 assert(PyTuple_Check(pto->args));
Alexander Belopolskye49af342015-03-01 15:08:17 -0500117 }
Alexander Belopolskye49af342015-03-01 15:08:17 -0500118
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200119 if (pkw == NULL || PyDict_GET_SIZE(pkw) == 0) {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200120 if (kw == NULL) {
121 pto->kw = PyDict_New();
Alexander Belopolskye49af342015-03-01 15:08:17 -0500122 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +0200123 else if (Py_REFCNT(kw) == 1) {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200124 Py_INCREF(kw);
125 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000126 }
Serhiy Storchaka9639e4a2017-02-20 14:04:30 +0200127 else {
128 pto->kw = PyDict_Copy(kw);
129 }
Alexander Belopolskye49af342015-03-01 15:08:17 -0500130 }
131 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200132 pto->kw = PyDict_Copy(pkw);
133 if (kw != NULL && pto->kw != NULL) {
134 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -0400135 Py_DECREF(pto);
136 return NULL;
137 }
138 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200140 if (pto->kw == NULL) {
141 Py_DECREF(pto);
142 return NULL;
143 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000144
Jeroen Demeyered184c02019-07-13 16:39:18 +0200145 partial_setvectorcall(pto);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000146 return (PyObject *)pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000147}
148
149static void
150partial_dealloc(partialobject *pto)
151{
Hai Shidd391232020-12-29 20:45:07 +0800152 PyTypeObject *tp = Py_TYPE(pto);
INADA Naokia6296d32017-08-24 14:55:17 +0900153 /* bpo-31095: UnTrack is needed before calling any callbacks */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000154 PyObject_GC_UnTrack(pto);
155 if (pto->weakreflist != NULL)
156 PyObject_ClearWeakRefs((PyObject *) pto);
157 Py_XDECREF(pto->fn);
158 Py_XDECREF(pto->args);
159 Py_XDECREF(pto->kw);
160 Py_XDECREF(pto->dict);
Hai Shidd391232020-12-29 20:45:07 +0800161 tp->tp_free(pto);
162 Py_DECREF(tp);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000163}
164
Jeroen Demeyered184c02019-07-13 16:39:18 +0200165
166/* Merging keyword arguments using the vectorcall convention is messy, so
167 * if we would need to do that, we stop using vectorcall and fall back
168 * to using partial_call() instead. */
169_Py_NO_INLINE static PyObject *
Victor Stinner7e433732019-11-08 10:05:17 +0100170partial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto,
171 PyObject *const *args, size_t nargsf,
172 PyObject *kwnames)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000173{
Jeroen Demeyered184c02019-07-13 16:39:18 +0200174 pto->vectorcall = NULL;
175 Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
Victor Stinner7e433732019-11-08 10:05:17 +0100176 return _PyObject_MakeTpCall(tstate, (PyObject *)pto,
177 args, nargs, kwnames);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200178}
179
180static PyObject *
181partial_vectorcall(partialobject *pto, PyObject *const *args,
182 size_t nargsf, PyObject *kwnames)
183{
Victor Stinner7e433732019-11-08 10:05:17 +0100184 PyThreadState *tstate = _PyThreadState_GET();
185
Jeroen Demeyered184c02019-07-13 16:39:18 +0200186 /* pto->kw is mutable, so need to check every time */
187 if (PyDict_GET_SIZE(pto->kw)) {
Victor Stinner7e433732019-11-08 10:05:17 +0100188 return partial_vectorcall_fallback(tstate, pto, args, nargsf, kwnames);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200189 }
190
191 Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
192 Py_ssize_t nargs_total = nargs;
193 if (kwnames != NULL) {
194 nargs_total += PyTuple_GET_SIZE(kwnames);
195 }
196
197 PyObject **pto_args = _PyTuple_ITEMS(pto->args);
198 Py_ssize_t pto_nargs = PyTuple_GET_SIZE(pto->args);
199
200 /* Fast path if we're called without arguments */
201 if (nargs_total == 0) {
Victor Stinner7e433732019-11-08 10:05:17 +0100202 return _PyObject_VectorcallTstate(tstate, pto->fn,
203 pto_args, pto_nargs, NULL);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200204 }
205
206 /* Fast path using PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
207 * positional argument */
208 if (pto_nargs == 1 && (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET)) {
209 PyObject **newargs = (PyObject **)args - 1;
210 PyObject *tmp = newargs[0];
211 newargs[0] = pto_args[0];
Victor Stinner7e433732019-11-08 10:05:17 +0100212 PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn,
213 newargs, nargs + 1, kwnames);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200214 newargs[0] = tmp;
215 return ret;
216 }
217
218 Py_ssize_t newnargs_total = pto_nargs + nargs_total;
219
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100220 PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000221 PyObject *ret;
Jeroen Demeyered184c02019-07-13 16:39:18 +0200222 PyObject **stack;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100223
Jeroen Demeyered184c02019-07-13 16:39:18 +0200224 if (newnargs_total <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
225 stack = small_stack;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100226 }
227 else {
Jeroen Demeyered184c02019-07-13 16:39:18 +0200228 stack = PyMem_Malloc(newnargs_total * sizeof(PyObject *));
229 if (stack == NULL) {
230 PyErr_NoMemory();
231 return NULL;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100232 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100233 }
234
Jeroen Demeyered184c02019-07-13 16:39:18 +0200235 /* Copy to new stack, using borrowed references */
236 memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
237 memcpy(stack + pto_nargs, args, nargs_total * sizeof(PyObject*));
238
Victor Stinner7e433732019-11-08 10:05:17 +0100239 ret = _PyObject_VectorcallTstate(tstate, pto->fn,
240 stack, pto_nargs + nargs, kwnames);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200241 if (stack != small_stack) {
242 PyMem_Free(stack);
243 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100244 return ret;
245}
246
Jeroen Demeyered184c02019-07-13 16:39:18 +0200247/* Set pto->vectorcall depending on the parameters of the partial object */
248static void
249partial_setvectorcall(partialobject *pto)
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100250{
Petr Viktorinffd97532020-02-11 17:46:57 +0100251 if (PyVectorcall_Function(pto->fn) == NULL) {
Jeroen Demeyered184c02019-07-13 16:39:18 +0200252 /* Don't use vectorcall if the underlying function doesn't support it */
253 pto->vectorcall = NULL;
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100254 }
Jeroen Demeyered184c02019-07-13 16:39:18 +0200255 /* We could have a special case if there are no arguments,
256 * but that is unlikely (why use partial without arguments?),
257 * so we don't optimize that */
258 else {
259 pto->vectorcall = (vectorcallfunc)partial_vectorcall;
260 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100261}
262
Jeroen Demeyered184c02019-07-13 16:39:18 +0200263
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100264static PyObject *
265partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
266{
Jeroen Demeyered184c02019-07-13 16:39:18 +0200267 assert(PyCallable_Check(pto->fn));
268 assert(PyTuple_Check(pto->args));
269 assert(PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000270
Jeroen Demeyered184c02019-07-13 16:39:18 +0200271 /* Merge keywords */
272 PyObject *kwargs2;
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +0200273 if (PyDict_GET_SIZE(pto->kw) == 0) {
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100274 /* kwargs can be NULL */
275 kwargs2 = kwargs;
276 Py_XINCREF(kwargs2);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200277 }
278 else {
Victor Stinner561ca802017-02-23 18:26:43 +0100279 /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
280 copied, because a function using "**kwargs" can modify the
281 dictionary. */
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100282 kwargs2 = PyDict_Copy(pto->kw);
283 if (kwargs2 == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284 return NULL;
285 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200286
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100287 if (kwargs != NULL) {
288 if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
289 Py_DECREF(kwargs2);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000290 return NULL;
291 }
292 }
293 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000294
Jeroen Demeyered184c02019-07-13 16:39:18 +0200295 /* Merge positional arguments */
296 /* Note: tupleconcat() is optimized for empty tuples */
297 PyObject *args2 = PySequence_Concat(pto->args, args);
298 if (args2 == NULL) {
299 Py_XDECREF(kwargs2);
300 return NULL;
301 }
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100302
Jeroen Demeyered184c02019-07-13 16:39:18 +0200303 PyObject *res = PyObject_Call(pto->fn, args2, kwargs2);
304 Py_DECREF(args2);
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100305 Py_XDECREF(kwargs2);
306 return res;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000307}
308
309static int
310partial_traverse(partialobject *pto, visitproc visit, void *arg)
311{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 Py_VISIT(pto->fn);
313 Py_VISIT(pto->args);
314 Py_VISIT(pto->kw);
315 Py_VISIT(pto->dict);
316 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000317}
318
319PyDoc_STRVAR(partial_doc,
320"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000321 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000322
323#define OFF(x) offsetof(partialobject, x)
324static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 {"func", T_OBJECT, OFF(fn), READONLY,
326 "function object to use in future partial calls"},
327 {"args", T_OBJECT, OFF(args), READONLY,
328 "tuple of arguments to future partial calls"},
329 {"keywords", T_OBJECT, OFF(kw), READONLY,
330 "dictionary of keyword arguments to future partial calls"},
Hai Shidd391232020-12-29 20:45:07 +0800331 {"__weaklistoffset__", T_PYSSIZET,
332 offsetof(partialobject, weakreflist), READONLY},
333 {"__dictoffset__", T_PYSSIZET,
334 offsetof(partialobject, dict), READONLY},
335 {"__vectorcalloffset__", T_PYSSIZET,
336 offsetof(partialobject, vectorcall), READONLY},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000337 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000338};
339
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000340static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500341 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000342 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000343};
344
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000345static PyObject *
346partial_repr(partialobject *pto)
347{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300348 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000349 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000350 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200351 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300352 int status;
353
354 status = Py_ReprEnter((PyObject *)pto);
355 if (status != 0) {
356 if (status < 0)
357 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000358 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300359 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000360
361 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300362 if (arglist == NULL)
363 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000364 /* Pack positional arguments */
365 assert (PyTuple_Check(pto->args));
366 n = PyTuple_GET_SIZE(pto->args);
367 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300368 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
369 PyTuple_GET_ITEM(pto->args, i)));
370 if (arglist == NULL)
371 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000372 }
373 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200374 assert (PyDict_Check(pto->kw));
375 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Michael Seifert6c3d5272017-03-15 06:26:33 +0100376 /* Prevent key.__str__ from deleting the value. */
377 Py_INCREF(value);
378 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300379 key, value));
Michael Seifert6c3d5272017-03-15 06:26:33 +0100380 Py_DECREF(value);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300381 if (arglist == NULL)
382 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000383 }
384 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
385 pto->fn, arglist);
386 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300387
388 done:
389 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000390 return result;
391}
392
Jack Diederiche0cbd692009-04-01 04:27:09 +0000393/* Pickle strategy:
394 __reduce__ by itself doesn't support getting kwargs in the unpickle
395 operation so we define a __setstate__ that replaces all the information
396 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200397 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000398 */
399
Antoine Pitrou69f71142009-05-24 21:25:49 +0000400static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000401partial_reduce(partialobject *pto, PyObject *unused)
402{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000403 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
404 pto->args, pto->kw,
405 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000406}
407
Antoine Pitrou69f71142009-05-24 21:25:49 +0000408static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200409partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000410{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000411 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200412
413 if (!PyTuple_Check(state) ||
414 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
415 !PyCallable_Check(fn) ||
416 !PyTuple_Check(fnargs) ||
417 (kw != Py_None && !PyDict_Check(kw)))
418 {
419 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000420 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000421 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200422
423 if(!PyTuple_CheckExact(fnargs))
424 fnargs = PySequence_Tuple(fnargs);
425 else
426 Py_INCREF(fnargs);
427 if (fnargs == NULL)
428 return NULL;
429
430 if (kw == Py_None)
431 kw = PyDict_New();
432 else if(!PyDict_CheckExact(kw))
433 kw = PyDict_Copy(kw);
434 else
435 Py_INCREF(kw);
436 if (kw == NULL) {
437 Py_DECREF(fnargs);
438 return NULL;
439 }
440
Serhiy Storchaka38741282016-02-02 18:45:17 +0200441 if (dict == Py_None)
442 dict = NULL;
443 else
444 Py_INCREF(dict);
445
Victor Stinner0f7b0b32017-03-14 21:37:20 +0100446 Py_INCREF(fn);
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300447 Py_SETREF(pto->fn, fn);
448 Py_SETREF(pto->args, fnargs);
449 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300450 Py_XSETREF(pto->dict, dict);
Jeroen Demeyered184c02019-07-13 16:39:18 +0200451 partial_setvectorcall(pto);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000452 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000453}
454
455static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000456 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200457 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Ethan Smithcecf0492020-04-13 21:53:04 -0700458 {"__class_getitem__", (PyCFunction)Py_GenericAlias,
459 METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000460 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000461};
462
Hai Shidd391232020-12-29 20:45:07 +0800463static PyType_Slot partial_type_slots[] = {
464 {Py_tp_dealloc, partial_dealloc},
465 {Py_tp_repr, partial_repr},
466 {Py_tp_call, partial_call},
467 {Py_tp_getattro, PyObject_GenericGetAttr},
468 {Py_tp_setattro, PyObject_GenericSetAttr},
469 {Py_tp_doc, (void *)partial_doc},
470 {Py_tp_traverse, partial_traverse},
471 {Py_tp_methods, partial_methods},
472 {Py_tp_members, partial_memberlist},
473 {Py_tp_getset, partial_getsetlist},
474 {Py_tp_new, partial_new},
475 {Py_tp_free, PyObject_GC_Del},
476 {0, 0}
477};
478
479static PyType_Spec partial_type_spec = {
480 .name = "functools.partial",
481 .basicsize = sizeof(partialobject),
482 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
483 Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
484 .slots = partial_type_slots
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000485};
486
487
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700488/* cmp_to_key ***************************************************************/
489
490typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200491 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700492 PyObject *cmp;
493 PyObject *object;
494} keyobject;
495
Hai Shidd391232020-12-29 20:45:07 +0800496static int
497keyobject_clear(keyobject *ko)
498{
499 Py_CLEAR(ko->cmp);
500 Py_CLEAR(ko->object);
501 return 0;
502}
503
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700504static void
505keyobject_dealloc(keyobject *ko)
506{
Hai Shidd391232020-12-29 20:45:07 +0800507 PyTypeObject *tp = Py_TYPE(ko);
508 keyobject_clear(ko);
Victor Stinner32bd68c2020-12-01 10:37:39 +0100509 PyObject_Free(ko);
Hai Shidd391232020-12-29 20:45:07 +0800510 Py_DECREF(tp);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700511}
512
513static int
514keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
515{
516 Py_VISIT(ko->cmp);
Hai Shi47a23fc2020-06-07 20:05:36 +0800517 Py_VISIT(ko->object);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700518 return 0;
519}
520
521static PyMemberDef keyobject_members[] = {
522 {"obj", T_OBJECT,
523 offsetof(keyobject, object), 0,
524 PyDoc_STR("Value wrapped by a key function.")},
525 {NULL}
526};
527
528static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700529keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700530
531static PyObject *
532keyobject_richcompare(PyObject *ko, PyObject *other, int op);
533
Hai Shidd391232020-12-29 20:45:07 +0800534static PyType_Slot keyobject_type_slots[] = {
535 {Py_tp_dealloc, keyobject_dealloc},
536 {Py_tp_call, keyobject_call},
537 {Py_tp_getattro, PyObject_GenericGetAttr},
538 {Py_tp_traverse, keyobject_traverse},
539 {Py_tp_clear, keyobject_clear},
540 {Py_tp_richcompare, keyobject_richcompare},
541 {Py_tp_members, keyobject_members},
542 {0, 0}
543};
544
545static PyType_Spec keyobject_type_spec = {
546 .name = "functools.KeyWrapper",
547 .basicsize = sizeof(keyobject),
548 .flags = Py_TPFLAGS_DEFAULT,
549 .slots = keyobject_type_slots
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700550};
551
552static PyObject *
553keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
554{
555 PyObject *object;
556 keyobject *result;
557 static char *kwargs[] = {"obj", NULL};
558
559 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
560 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800561
562 result = PyObject_New(keyobject, Py_TYPE(ko));
563 if (result == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700564 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800565 }
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700566 Py_INCREF(ko->cmp);
567 result->cmp = ko->cmp;
568 Py_INCREF(object);
569 result->object = object;
570 return (PyObject *)result;
571}
572
573static PyObject *
574keyobject_richcompare(PyObject *ko, PyObject *other, int op)
575{
576 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700577 PyObject *x;
578 PyObject *y;
579 PyObject *compare;
580 PyObject *answer;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200581 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700582
Hai Shidd391232020-12-29 20:45:07 +0800583 if (!Py_IS_TYPE(other, Py_TYPE(ko))) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700584 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
585 return NULL;
586 }
587 compare = ((keyobject *) ko)->cmp;
588 assert(compare != NULL);
589 x = ((keyobject *) ko)->object;
590 y = ((keyobject *) other)->object;
591 if (!x || !y){
592 PyErr_Format(PyExc_AttributeError, "object");
593 return NULL;
594 }
595
596 /* Call the user's comparison function and translate the 3-way
597 * result into true or false (or error).
598 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200599 stack[0] = x;
600 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200601 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200602 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700603 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200604 }
605
Victor Stinner37834132020-10-27 17:12:53 +0100606 answer = PyObject_RichCompare(res, _PyLong_GetZero(), op);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700607 Py_DECREF(res);
608 return answer;
609}
610
611static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200612functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
613{
614 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700615 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200616 keyobject *object;
Hai Shidd391232020-12-29 20:45:07 +0800617 _functools_state *state;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700618
619 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
620 return NULL;
Hai Shidd391232020-12-29 20:45:07 +0800621
622 state = get_functools_state(self);
623 object = PyObject_New(keyobject, state->keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700624 if (!object)
625 return NULL;
626 Py_INCREF(cmp);
627 object->cmp = cmp;
628 object->object = NULL;
629 return (PyObject *)object;
630}
631
632PyDoc_STRVAR(functools_cmp_to_key_doc,
633"Convert a cmp= function into a key= function.");
634
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000635/* reduce (used to be a builtin) ********************************************/
636
637static PyObject *
638functools_reduce(PyObject *self, PyObject *args)
639{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000640 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000641
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000642 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
643 return NULL;
644 if (result != NULL)
645 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000646
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000647 it = PyObject_GetIter(seq);
648 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000649 if (PyErr_ExceptionMatches(PyExc_TypeError))
650 PyErr_SetString(PyExc_TypeError,
651 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000652 Py_XDECREF(result);
653 return NULL;
654 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000655
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000656 if ((args = PyTuple_New(2)) == NULL)
657 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000658
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000659 for (;;) {
660 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000661
Victor Stinnera93c51e2020-02-07 00:38:59 +0100662 if (Py_REFCNT(args) > 1) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000663 Py_DECREF(args);
664 if ((args = PyTuple_New(2)) == NULL)
665 goto Fail;
666 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000667
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000668 op2 = PyIter_Next(it);
669 if (op2 == NULL) {
670 if (PyErr_Occurred())
671 goto Fail;
672 break;
673 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000674
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000675 if (result == NULL)
676 result = op2;
677 else {
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500678 /* Update the args tuple in-place */
Victor Stinnera93c51e2020-02-07 00:38:59 +0100679 assert(Py_REFCNT(args) == 1);
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500680 Py_XSETREF(_PyTuple_ITEMS(args)[0], result);
681 Py_XSETREF(_PyTuple_ITEMS(args)[1], op2);
682 if ((result = PyObject_Call(func, args, NULL)) == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000683 goto Fail;
Sergey Fedoseeve5f62072019-06-02 01:32:18 +0500684 }
Brandt Bucher226a0122020-12-04 19:45:57 -0800685 // bpo-42536: The GC may have untracked this args tuple. Since we're
686 // recycling it, make sure it's tracked again:
687 if (!_PyObject_GC_IS_TRACKED(args)) {
688 _PyObject_GC_TRACK(args);
689 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000690 }
691 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000692
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000693 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000694
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000695 if (result == NULL)
696 PyErr_SetString(PyExc_TypeError,
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600697 "reduce() of empty iterable with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000698
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000699 Py_DECREF(it);
700 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000701
702Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000703 Py_XDECREF(args);
704 Py_XDECREF(result);
705 Py_DECREF(it);
706 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000707}
708
709PyDoc_STRVAR(functools_reduce_doc,
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600710"reduce(function, iterable[, initial]) -> value\n\
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000711\n\
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600712Apply a function of two arguments cumulatively to the items of a sequence\n\
713or iterable, from left to right, so as to reduce the iterable to a single\n\
714value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000715((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
Zackery Spytzcd3c2bd2020-06-28 00:40:54 -0600716of the iterable in the calculation, and serves as a default when the\n\
717iterable is empty.");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000718
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300719/* lru_cache object **********************************************************/
720
Raymond Hettinger2dda72a2019-02-08 18:55:02 -0800721/* There are four principal algorithmic differences from the pure python version:
722
723 1). The C version relies on the GIL instead of having its own reentrant lock.
724
725 2). The prev/next link fields use borrowed references.
726
727 3). For a full cache, the pure python version rotates the location of the
728 root entry so that it never has to move individual links and it can
729 limit updates to just the key and result fields. However, in the C
730 version, links are temporarily removed while the cache dict updates are
731 occurring. Afterwards, they are appended or prepended back into the
732 doubly-linked lists.
733
734 4) In the Python version, the _HashSeq class is used to prevent __hash__
735 from being called more than once. In the C version, the "known hash"
736 variants of dictionary calls as used to the same effect.
737
738*/
739
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300740struct lru_list_elem;
741struct lru_cache_object;
742
743typedef struct lru_list_elem {
744 PyObject_HEAD
745 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300746 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300747 PyObject *key, *result;
748} lru_list_elem;
749
750static void
751lru_list_elem_dealloc(lru_list_elem *link)
752{
Hai Shidd391232020-12-29 20:45:07 +0800753 PyTypeObject *tp = Py_TYPE(link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300754 Py_XDECREF(link->key);
755 Py_XDECREF(link->result);
Victor Stinner32bd68c2020-12-01 10:37:39 +0100756 PyObject_Free(link);
Hai Shidd391232020-12-29 20:45:07 +0800757 Py_DECREF(tp);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300758}
759
Hai Shidd391232020-12-29 20:45:07 +0800760static PyType_Slot lru_list_elem_type_slots[] = {
761 {Py_tp_dealloc, lru_list_elem_dealloc},
762 {0, 0}
763};
764
765static PyType_Spec lru_list_elem_type_spec = {
766 .name = "functools._lru_list_elem",
767 .basicsize = sizeof(lru_list_elem),
768 .flags = Py_TPFLAGS_DEFAULT,
769 .slots = lru_list_elem_type_slots
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300770};
771
772
773typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
774
775typedef struct lru_cache_object {
776 lru_list_elem root; /* includes PyObject_HEAD */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300777 lru_cache_ternaryfunc wrapper;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300778 int typed;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500779 PyObject *cache;
780 Py_ssize_t hits;
781 PyObject *func;
782 Py_ssize_t maxsize;
783 Py_ssize_t misses;
784 PyObject *cache_info_type;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300785 PyObject *dict;
Dennis Sweeney1253c3e2020-05-05 17:14:32 -0400786 PyObject *weakreflist;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300787} lru_cache_object;
788
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300789static PyObject *
Hai Shidd391232020-12-29 20:45:07 +0800790lru_cache_make_key(_functools_state *state, PyObject *args,
791 PyObject *kwds, int typed)
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300792{
Raymond Hettingerdda44682017-01-08 18:04:30 -0800793 PyObject *key, *keyword, *value;
794 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300795
Raymond Hettinger14adbd42019-04-20 07:20:44 -1000796 kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
797
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300798 /* short path, key will match args anyway, which is a tuple */
Raymond Hettinger14adbd42019-04-20 07:20:44 -1000799 if (!typed && !kwds_size) {
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500800 if (PyTuple_GET_SIZE(args) == 1) {
801 key = PyTuple_GET_ITEM(args, 0);
802 if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) {
803 /* For common scalar keys, save space by
804 dropping the enclosing args tuple */
805 Py_INCREF(key);
806 return key;
807 }
808 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300809 Py_INCREF(args);
810 return args;
811 }
812
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300813 key_size = PyTuple_GET_SIZE(args);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800814 if (kwds_size)
815 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300816 if (typed)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800817 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300818
819 key = PyTuple_New(key_size);
820 if (key == NULL)
Raymond Hettingerdda44682017-01-08 18:04:30 -0800821 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300822
823 key_pos = 0;
824 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
825 PyObject *item = PyTuple_GET_ITEM(args, pos);
826 Py_INCREF(item);
827 PyTuple_SET_ITEM(key, key_pos++, item);
828 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800829 if (kwds_size) {
Hai Shidd391232020-12-29 20:45:07 +0800830 Py_INCREF(state->kwd_mark);
831 PyTuple_SET_ITEM(key, key_pos++, state->kwd_mark);
Raymond Hettingerdda44682017-01-08 18:04:30 -0800832 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
833 Py_INCREF(keyword);
834 PyTuple_SET_ITEM(key, key_pos++, keyword);
835 Py_INCREF(value);
836 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300837 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800838 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300839 }
840 if (typed) {
841 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
842 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
843 Py_INCREF(item);
844 PyTuple_SET_ITEM(key, key_pos++, item);
845 }
Raymond Hettingerdda44682017-01-08 18:04:30 -0800846 if (kwds_size) {
847 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
848 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300849 Py_INCREF(item);
850 PyTuple_SET_ITEM(key, key_pos++, item);
851 }
852 }
853 }
854 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300855 return key;
856}
857
858static PyObject *
859uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
860{
Raymond Hettingerffdf1c32019-01-31 15:03:38 -0800861 PyObject *result;
862
863 self->misses++;
864 result = PyObject_Call(self->func, args, kwds);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300865 if (!result)
866 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300867 return result;
868}
869
870static PyObject *
871infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
872{
873 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300874 Py_hash_t hash;
Hai Shidd391232020-12-29 20:45:07 +0800875 _functools_state *state;
876 state = get_functools_state_by_type(Py_TYPE(self));
877 if (state == NULL) {
878 return NULL;
879 }
880 PyObject *key = lru_cache_make_key(state, args, kwds, self->typed);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300881 if (!key)
882 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300883 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500884 if (hash == -1) {
885 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300886 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500887 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300888 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300889 if (result) {
890 Py_INCREF(result);
891 self->hits++;
892 Py_DECREF(key);
893 return result;
894 }
895 if (PyErr_Occurred()) {
896 Py_DECREF(key);
897 return NULL;
898 }
Raymond Hettingerffdf1c32019-01-31 15:03:38 -0800899 self->misses++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300900 result = PyObject_Call(self->func, args, kwds);
901 if (!result) {
902 Py_DECREF(key);
903 return NULL;
904 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300905 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300906 Py_DECREF(result);
907 Py_DECREF(key);
908 return NULL;
909 }
910 Py_DECREF(key);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300911 return result;
912}
913
914static void
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500915lru_cache_extract_link(lru_list_elem *link)
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300916{
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500917 lru_list_elem *link_prev = link->prev;
918 lru_list_elem *link_next = link->next;
919 link_prev->next = link->next;
920 link_next->prev = link->prev;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300921}
922
923static void
924lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
925{
926 lru_list_elem *root = &self->root;
927 lru_list_elem *last = root->prev;
928 last->next = root->prev = link;
929 link->prev = last;
930 link->next = root;
931}
932
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500933static void
934lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
935{
936 lru_list_elem *root = &self->root;
937 lru_list_elem *first = root->next;
938 first->prev = root->next = link;
939 link->prev = root;
940 link->next = first;
941}
942
943/* General note on reentrancy:
944
945 There are four dictionary calls in the bounded_lru_cache_wrapper():
946 1) The initial check for a cache match. 2) The post user-function
947 check for a cache match. 3) The deletion of the oldest entry.
948 4) The addition of the newest entry.
949
950 In all four calls, we have a known hash which lets use avoid a call
951 to __hash__(). That leaves only __eq__ as a possible source of a
952 reentrant call.
953
954 The __eq__ method call is always made for a cache hit (dict access #1).
955 Accordingly, we have make sure not modify the cache state prior to
956 this call.
957
958 The __eq__ method call is never made for the deletion (dict access #3)
959 because it is an identity match.
960
961 For the other two accesses (#2 and #4), calls to __eq__ only occur
962 when some other entry happens to have an exactly matching hash (all
963 64-bits). Though rare, this can happen, so we have to make sure to
964 either call it at the top of its code path before any cache
965 state modifications (dict access #2) or be prepared to restore
966 invariants at the end of the code path (dict access #4).
967
968 Another possible source of reentrancy is a decref which can trigger
969 arbitrary code execution. To make the code easier to reason about,
970 the decrefs are deferred to the end of the each possible code path
971 so that we know the cache is a consistent state.
972 */
973
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300974static PyObject *
975bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
976{
977 lru_list_elem *link;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500978 PyObject *key, *result, *testresult;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300979 Py_hash_t hash;
Hai Shidd391232020-12-29 20:45:07 +0800980 _functools_state *state;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300981
Hai Shidd391232020-12-29 20:45:07 +0800982 state = get_functools_state_by_type(Py_TYPE(self));
983 if (state == NULL) {
984 return NULL;
985 }
986 key = lru_cache_make_key(state, args, kwds, self->typed);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300987 if (!key)
988 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300989 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500990 if (hash == -1) {
991 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300992 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500993 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300994 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500995 if (link != NULL) {
996 lru_cache_extract_link(link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300997 lru_cache_append_link(self, link);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300998 result = link->result;
Raymond Hettingerd8080c02019-01-26 03:02:00 -0500999 self->hits++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001000 Py_INCREF(result);
1001 Py_DECREF(key);
1002 return result;
1003 }
1004 if (PyErr_Occurred()) {
1005 Py_DECREF(key);
1006 return NULL;
1007 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001008 self->misses++;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001009 result = PyObject_Call(self->func, args, kwds);
1010 if (!result) {
1011 Py_DECREF(key);
1012 return NULL;
1013 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001014 testresult = _PyDict_GetItem_KnownHash(self->cache, key, hash);
1015 if (testresult != NULL) {
1016 /* Getting here means that this same key was added to the cache
1017 during the PyObject_Call(). Since the link update is already
1018 done, we need only return the computed result. */
1019 Py_DECREF(key);
1020 return result;
1021 }
1022 if (PyErr_Occurred()) {
1023 /* This is an unusual case since this same lookup
1024 did not previously trigger an error during lookup.
1025 Treat it the same as an error in user function
1026 and return with the error set. */
1027 Py_DECREF(key);
1028 Py_DECREF(result);
1029 return NULL;
1030 }
1031 /* This is the normal case. The new key wasn't found before
1032 user function call and it is still not there. So we
1033 proceed normally and update the cache with the new result. */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001034
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001035 assert(self->maxsize > 0);
1036 if (PyDict_GET_SIZE(self->cache) < self->maxsize ||
1037 self->root.next == &self->root)
1038 {
1039 /* Cache is not full, so put the result in a new link */
INADA Naoki3070b712017-12-26 02:03:24 +09001040 link = (lru_list_elem *)PyObject_New(lru_list_elem,
Hai Shidd391232020-12-29 20:45:07 +08001041 state->lru_list_elem_type);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001042 if (link == NULL) {
1043 Py_DECREF(key);
1044 Py_DECREF(result);
1045 return NULL;
1046 }
1047
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001048 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001049 link->key = key;
1050 link->result = result;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001051 /* What is really needed here is a SetItem variant with a "no clobber"
1052 option. If the __eq__ call triggers a reentrant call that adds
1053 this same key, then this setitem call will update the cache dict
1054 with this new link, leaving the old link as an orphan (i.e. not
1055 having a cache dict entry that refers to it). */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +03001056 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
1057 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001058 Py_DECREF(link);
1059 return NULL;
1060 }
1061 lru_cache_append_link(self, link);
1062 Py_INCREF(result); /* for return */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001063 return result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001064 }
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001065 /* Since the cache is full, we need to evict an old key and add
1066 a new key. Rather than free the old link and allocate a new
1067 one, we reuse the link for the new key and result and move it
1068 to front of the cache to mark it as recently used.
1069
1070 We try to assure all code paths (including errors) leave all
1071 of the links in place. Either the link is successfully
1072 updated and moved or it is restored to its old position.
1073 However if an unrecoverable error is found, it doesn't
1074 make sense to reinsert the link, so we leave it out
1075 and the cache will no longer register as full.
1076 */
1077 PyObject *oldkey, *oldresult, *popresult;
1078
1079 /* Extract the oldest item. */
1080 assert(self->root.next != &self->root);
1081 link = self->root.next;
1082 lru_cache_extract_link(link);
1083 /* Remove it from the cache.
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001084 The cache dict holds one reference to the link.
1085 We created one other reference when the link was created.
1086 The linked list only has borrowed references. */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001087 popresult = _PyDict_Pop_KnownHash(self->cache, link->key,
1088 link->hash, Py_None);
1089 if (popresult == Py_None) {
1090 /* Getting here means that the user function call or another
1091 thread has already removed the old key from the dictionary.
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001092 This link is now an orphan. Since we don't want to leave the
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001093 cache in an inconsistent state, we don't restore the link. */
1094 Py_DECREF(popresult);
1095 Py_DECREF(link);
1096 Py_DECREF(key);
1097 return result;
1098 }
1099 if (popresult == NULL) {
1100 /* An error arose while trying to remove the oldest key (the one
1101 being evicted) from the cache. We restore the link to its
1102 original position as the oldest link. Then we allow the
1103 error propagate upward; treating it the same as an error
1104 arising in the user function. */
1105 lru_cache_prepend_link(self, link);
1106 Py_DECREF(key);
1107 Py_DECREF(result);
1108 return NULL;
1109 }
1110 /* Keep a reference to the old key and old result to prevent their
1111 ref counts from going to zero during the update. That will
1112 prevent potentially arbitrary object clean-up code (i.e. __del__)
1113 from running while we're still adjusting the links. */
1114 oldkey = link->key;
1115 oldresult = link->result;
1116
1117 link->hash = hash;
1118 link->key = key;
1119 link->result = result;
1120 /* Note: The link is being added to the cache dict without the
1121 prev and next fields set to valid values. We have to wait
1122 for successful insertion in the cache dict before adding the
1123 link to the linked list. Otherwise, the potentially reentrant
Raymond Hettinger2dda72a2019-02-08 18:55:02 -08001124 __eq__ call could cause the then orphan link to be visited. */
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001125 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
1126 hash) < 0) {
1127 /* Somehow the cache dict update failed. We no longer can
1128 restore the old link. Let the error propagate upward and
1129 leave the cache short one link. */
1130 Py_DECREF(popresult);
1131 Py_DECREF(link);
1132 Py_DECREF(oldkey);
1133 Py_DECREF(oldresult);
1134 return NULL;
1135 }
1136 lru_cache_append_link(self, link);
1137 Py_INCREF(result); /* for return */
1138 Py_DECREF(popresult);
1139 Py_DECREF(oldkey);
1140 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001141 return result;
1142}
1143
1144static PyObject *
1145lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
1146{
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001147 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001148 int typed;
1149 lru_cache_object *obj;
1150 Py_ssize_t maxsize;
1151 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
1152 static char *keywords[] = {"user_function", "maxsize", "typed",
1153 "cache_info_type", NULL};
1154
1155 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
1156 &func, &maxsize_O, &typed,
1157 &cache_info_type)) {
1158 return NULL;
1159 }
1160
1161 if (!PyCallable_Check(func)) {
1162 PyErr_SetString(PyExc_TypeError,
1163 "the first argument must be callable");
1164 return NULL;
1165 }
1166
1167 /* select the caching function, and make/inc maxsize_O */
1168 if (maxsize_O == Py_None) {
1169 wrapper = infinite_lru_cache_wrapper;
1170 /* use this only to initialize lru_cache_object attribute maxsize */
1171 maxsize = -1;
1172 } else if (PyIndex_Check(maxsize_O)) {
1173 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1174 if (maxsize == -1 && PyErr_Occurred())
1175 return NULL;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001176 if (maxsize < 0) {
1177 maxsize = 0;
1178 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001179 if (maxsize == 0)
1180 wrapper = uncached_lru_cache_wrapper;
1181 else
1182 wrapper = bounded_lru_cache_wrapper;
1183 } else {
1184 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1185 return NULL;
1186 }
1187
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001188 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001189 return NULL;
1190
Serhiy Storchaka374164c2015-07-25 12:10:21 +03001191 obj = (lru_cache_object *)type->tp_alloc(type, 0);
1192 if (obj == NULL) {
1193 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001194 return NULL;
1195 }
1196
1197 obj->root.prev = &obj->root;
1198 obj->root.next = &obj->root;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001199 obj->wrapper = wrapper;
1200 obj->typed = typed;
1201 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001202 Py_INCREF(func);
1203 obj->func = func;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001204 obj->misses = obj->hits = 0;
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001205 obj->maxsize = maxsize;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001206 Py_INCREF(cache_info_type);
1207 obj->cache_info_type = cache_info_type;
Raymond Hettingerbba760e2020-04-20 13:47:12 -07001208 obj->dict = NULL;
Dennis Sweeney1253c3e2020-05-05 17:14:32 -04001209 obj->weakreflist = NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001210 return (PyObject *)obj;
1211}
1212
1213static lru_list_elem *
1214lru_cache_unlink_list(lru_cache_object *self)
1215{
1216 lru_list_elem *root = &self->root;
1217 lru_list_elem *link = root->next;
1218 if (link == root)
1219 return NULL;
1220 root->prev->next = NULL;
1221 root->next = root->prev = root;
1222 return link;
1223}
1224
1225static void
1226lru_cache_clear_list(lru_list_elem *link)
1227{
1228 while (link != NULL) {
1229 lru_list_elem *next = link->next;
1230 Py_DECREF(link);
1231 link = next;
1232 }
1233}
1234
Hai Shidd391232020-12-29 20:45:07 +08001235static int
1236lru_cache_tp_clear(lru_cache_object *self)
1237{
1238 lru_list_elem *list = lru_cache_unlink_list(self);
1239 Py_CLEAR(self->func);
1240 Py_CLEAR(self->cache);
1241 Py_CLEAR(self->cache_info_type);
1242 Py_CLEAR(self->dict);
1243 lru_cache_clear_list(list);
1244 return 0;
1245}
1246
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001247static void
1248lru_cache_dealloc(lru_cache_object *obj)
1249{
Hai Shidd391232020-12-29 20:45:07 +08001250 PyTypeObject *tp = Py_TYPE(obj);
INADA Naokia6296d32017-08-24 14:55:17 +09001251 /* bpo-31095: UnTrack is needed before calling any callbacks */
1252 PyObject_GC_UnTrack(obj);
Hai Shidd391232020-12-29 20:45:07 +08001253 if (obj->weakreflist != NULL) {
Dennis Sweeney1253c3e2020-05-05 17:14:32 -04001254 PyObject_ClearWeakRefs((PyObject*)obj);
Hai Shidd391232020-12-29 20:45:07 +08001255 }
INADA Naokia6296d32017-08-24 14:55:17 +09001256
Hai Shidd391232020-12-29 20:45:07 +08001257 lru_cache_tp_clear(obj);
1258 tp->tp_free(obj);
1259 Py_DECREF(tp);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001260}
1261
1262static PyObject *
1263lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1264{
1265 return self->wrapper(self, args, kwds);
1266}
1267
1268static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001269lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1270{
1271 if (obj == Py_None || obj == NULL) {
1272 Py_INCREF(self);
1273 return self;
1274 }
1275 return PyMethod_New(self, obj);
1276}
1277
1278static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001279lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1280{
Raymond Hettingerd8080c02019-01-26 03:02:00 -05001281 if (self->maxsize == -1) {
1282 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1283 self->hits, self->misses, Py_None,
1284 PyDict_GET_SIZE(self->cache));
1285 }
1286 return PyObject_CallFunction(self->cache_info_type, "nnnn",
1287 self->hits, self->misses, self->maxsize,
Serhiy Storchaka5ab81d72016-12-16 16:18:57 +02001288 PyDict_GET_SIZE(self->cache));
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001289}
1290
1291static PyObject *
1292lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1293{
1294 lru_list_elem *list = lru_cache_unlink_list(self);
1295 self->hits = self->misses = 0;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001296 PyDict_Clear(self->cache);
1297 lru_cache_clear_list(list);
1298 Py_RETURN_NONE;
1299}
1300
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001301static PyObject *
1302lru_cache_reduce(PyObject *self, PyObject *unused)
1303{
1304 return PyObject_GetAttrString(self, "__qualname__");
1305}
1306
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001307static PyObject *
1308lru_cache_copy(PyObject *self, PyObject *unused)
1309{
1310 Py_INCREF(self);
1311 return self;
1312}
1313
1314static PyObject *
1315lru_cache_deepcopy(PyObject *self, PyObject *unused)
1316{
1317 Py_INCREF(self);
1318 return self;
1319}
1320
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001321static int
1322lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1323{
1324 lru_list_elem *link = self->root.next;
1325 while (link != &self->root) {
1326 lru_list_elem *next = link->next;
INADA Naoki3070b712017-12-26 02:03:24 +09001327 Py_VISIT(link->key);
1328 Py_VISIT(link->result);
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001329 link = next;
1330 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001331 Py_VISIT(self->func);
1332 Py_VISIT(self->cache);
1333 Py_VISIT(self->cache_info_type);
1334 Py_VISIT(self->dict);
1335 return 0;
1336}
1337
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001338
1339PyDoc_STRVAR(lru_cache_doc,
1340"Create a cached callable that wraps another function.\n\
1341\n\
1342user_function: the function being cached\n\
1343\n\
1344maxsize: 0 for no caching\n\
1345 None for unlimited cache size\n\
1346 n for a bounded cache\n\
1347\n\
1348typed: False cache f(3) and f(3.0) as identical calls\n\
1349 True cache f(3) and f(3.0) as distinct calls\n\
1350\n\
1351cache_info_type: namedtuple class with the fields:\n\
1352 hits misses currsize maxsize\n"
1353);
1354
1355static PyMethodDef lru_cache_methods[] = {
1356 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1357 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001358 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001359 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1360 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001361 {NULL}
1362};
1363
1364static PyGetSetDef lru_cache_getsetlist[] = {
1365 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1366 {NULL}
1367};
1368
Hai Shidd391232020-12-29 20:45:07 +08001369static PyMemberDef lru_cache_memberlist[] = {
1370 {"__dictoffset__", T_PYSSIZET,
1371 offsetof(lru_cache_object, dict), READONLY},
1372 {"__weaklistoffset__", T_PYSSIZET,
1373 offsetof(lru_cache_object, weakreflist), READONLY},
1374 {NULL} /* Sentinel */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001375};
1376
Hai Shidd391232020-12-29 20:45:07 +08001377static PyType_Slot lru_cache_type_slots[] = {
1378 {Py_tp_dealloc, lru_cache_dealloc},
1379 {Py_tp_call, lru_cache_call},
1380 {Py_tp_doc, (void *)lru_cache_doc},
1381 {Py_tp_traverse, lru_cache_tp_traverse},
1382 {Py_tp_clear, lru_cache_tp_clear},
1383 {Py_tp_methods, lru_cache_methods},
1384 {Py_tp_members, lru_cache_memberlist},
1385 {Py_tp_getset, lru_cache_getsetlist},
1386 {Py_tp_descr_get, lru_cache_descr_get},
1387 {Py_tp_new, lru_cache_new},
1388 {0, 0}
1389};
1390
1391static PyType_Spec lru_cache_type_spec = {
1392 .name = "functools._lru_cache_wrapper",
1393 .basicsize = sizeof(lru_cache_object),
1394 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1395 Py_TPFLAGS_METHOD_DESCRIPTOR,
1396 .slots = lru_cache_type_slots
1397};
1398
1399
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001400/* module level code ********************************************************/
1401
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001402PyDoc_STRVAR(_functools_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001403"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001404
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001405static PyMethodDef _functools_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001406 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02001407 {"cmp_to_key", (PyCFunction)(void(*)(void))functools_cmp_to_key,
Victor Stinner446c8d52011-04-05 12:21:35 +02001408 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001409 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001410};
1411
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001412static int
1413_functools_exec(PyObject *module)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001414{
Hai Shidd391232020-12-29 20:45:07 +08001415 _functools_state *state = get_functools_state(module);
1416 state->kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
1417 if (state->kwd_mark == NULL) {
1418 return -1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001419 }
1420
Hai Shidd391232020-12-29 20:45:07 +08001421 state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1422 &partial_type_spec, NULL);
1423 if (state->partial_type == NULL) {
1424 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001425 }
Hai Shidd391232020-12-29 20:45:07 +08001426 if (PyModule_AddType(module, state->partial_type) < 0) {
1427 return -1;
1428 }
1429
1430 PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
1431 &lru_cache_type_spec, NULL);
1432 if (lru_cache_type == NULL) {
1433 return -1;
1434 }
1435 if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
1436 Py_DECREF(lru_cache_type);
1437 return -1;
1438 }
Victor Stinnerba0e49a2020-12-30 02:24:43 +01001439 Py_DECREF(lru_cache_type);
Hai Shidd391232020-12-29 20:45:07 +08001440
1441 state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1442 &keyobject_type_spec, NULL);
1443 if (state->keyobject_type == NULL) {
1444 return -1;
1445 }
1446 if (PyModule_AddType(module, state->keyobject_type) < 0) {
1447 return -1;
1448 }
1449
1450 state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
1451 module, &lru_list_elem_type_spec, NULL);
1452 if (state->lru_list_elem_type == NULL) {
1453 return -1;
1454 }
1455 if (PyModule_AddType(module, state->lru_list_elem_type) < 0) {
1456 return -1;
1457 }
1458
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001459 return 0;
1460}
1461
Hai Shidd391232020-12-29 20:45:07 +08001462static int
1463_functools_traverse(PyObject *module, visitproc visit, void *arg)
1464{
1465 _functools_state *state = get_functools_state(module);
1466 Py_VISIT(state->kwd_mark);
1467 Py_VISIT(state->partial_type);
1468 Py_VISIT(state->keyobject_type);
1469 Py_VISIT(state->lru_list_elem_type);
1470 return 0;
1471}
1472
1473static int
1474_functools_clear(PyObject *module)
1475{
1476 _functools_state *state = get_functools_state(module);
1477 Py_CLEAR(state->kwd_mark);
1478 Py_CLEAR(state->partial_type);
1479 Py_CLEAR(state->keyobject_type);
1480 Py_CLEAR(state->lru_list_elem_type);
1481 return 0;
1482}
1483
1484static void
1485_functools_free(void *module)
1486{
1487 _functools_clear((PyObject *)module);
1488}
1489
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001490static struct PyModuleDef_Slot _functools_slots[] = {
1491 {Py_mod_exec, _functools_exec},
1492 {0, NULL}
1493};
1494
1495static struct PyModuleDef _functools_module = {
1496 PyModuleDef_HEAD_INIT,
Hai Shidd391232020-12-29 20:45:07 +08001497 .m_name = "_functools",
1498 .m_doc = _functools_doc,
1499 .m_size = sizeof(_functools_state),
1500 .m_methods = _functools_methods,
1501 .m_slots = _functools_slots,
1502 .m_traverse = _functools_traverse,
1503 .m_clear = _functools_clear,
1504 .m_free = _functools_free,
Paulo Henrique Silva7dd549e2020-03-24 23:19:58 -03001505};
1506
1507PyMODINIT_FUNC
1508PyInit__functools(void)
1509{
1510 return PyModuleDef_Init(&_functools_module);
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001511}