Branch data Line data Source code
1 : : #include "Python.h"
2 : : #include "pycore_call.h" // _PyObject_CallNoArgs()
3 : : #include "pycore_dict.h" // _PyDict_Pop_KnownHash()
4 : : #include "pycore_long.h" // _PyLong_GetZero()
5 : : #include "pycore_moduleobject.h" // _PyModule_GetState()
6 : : #include "pycore_object.h" // _PyObject_GC_TRACK
7 : : #include "pycore_pystate.h" // _PyThreadState_GET()
8 : : #include "pycore_tuple.h" // _PyTuple_ITEMS()
9 : : #include "structmember.h" // PyMemberDef
10 : :
11 : : #include "clinic/_functoolsmodule.c.h"
12 : : /*[clinic input]
13 : : module _functools
14 : : class _functools._lru_cache_wrapper "PyObject *" "&lru_cache_type_spec"
15 : : [clinic start generated code]*/
16 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=bece4053896b09c0]*/
17 : :
18 : : /* _functools module written and maintained
19 : : by Hye-Shik Chang <perky@FreeBSD.org>
20 : : with adaptations by Raymond Hettinger <python@rcn.com>
21 : : Copyright (c) 2004, 2005, 2006 Python Software Foundation.
22 : : All rights reserved.
23 : : */
24 : :
25 : : typedef struct _functools_state {
26 : : /* this object is used delimit args and keywords in the cache keys */
27 : : PyObject *kwd_mark;
28 : : PyTypeObject *partial_type;
29 : : PyTypeObject *keyobject_type;
30 : : PyTypeObject *lru_list_elem_type;
31 : : } _functools_state;
32 : :
33 : : static inline _functools_state *
34 : 142 : get_functools_state(PyObject *module)
35 : : {
36 : 142 : void *state = _PyModule_GetState(module);
37 : : assert(state != NULL);
38 : 142 : return (_functools_state *)state;
39 : : }
40 : :
41 : :
42 : : /* partial object **********************************************************/
43 : :
44 : : typedef struct {
45 : : PyObject_HEAD
46 : : PyObject *fn;
47 : : PyObject *args;
48 : : PyObject *kw;
49 : : PyObject *dict; /* __dict__ */
50 : : PyObject *weakreflist; /* List of weak references */
51 : : vectorcallfunc vectorcall;
52 : : } partialobject;
53 : :
54 : : static void partial_setvectorcall(partialobject *pto);
55 : : static struct PyModuleDef _functools_module;
56 : : static PyObject *
57 : : partial_call(partialobject *pto, PyObject *args, PyObject *kwargs);
58 : :
59 : : static inline _functools_state *
60 : 38 : get_functools_state_by_type(PyTypeObject *type)
61 : : {
62 : 38 : PyObject *module = PyType_GetModuleByDef(type, &_functools_module);
63 [ - + ]: 38 : if (module == NULL) {
64 : 0 : return NULL;
65 : : }
66 : 38 : return get_functools_state(module);
67 : : }
68 : :
69 : : // Not converted to argument clinic, because of `*args, **kwargs` arguments.
70 : : static PyObject *
71 : 78 : partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
72 : : {
73 : : PyObject *func, *pargs, *nargs, *pkw;
74 : : partialobject *pto;
75 : :
76 [ - + ]: 78 : if (PyTuple_GET_SIZE(args) < 1) {
77 : 0 : PyErr_SetString(PyExc_TypeError,
78 : : "type 'partial' takes at least one argument");
79 : 0 : return NULL;
80 : : }
81 : :
82 : 78 : pargs = pkw = NULL;
83 : 78 : func = PyTuple_GET_ITEM(args, 0);
84 [ - + ]: 78 : if (Py_TYPE(func)->tp_call == (ternaryfunc)partial_call) {
85 : : // The type of "func" might not be exactly the same type object
86 : : // as "type", but if it is called using partial_call, it must have the
87 : : // same memory layout (fn, args and kw members).
88 : : // We can use its underlying function directly and merge the arguments.
89 : 0 : partialobject *part = (partialobject *)func;
90 [ # # ]: 0 : if (part->dict == NULL) {
91 : 0 : pargs = part->args;
92 : 0 : pkw = part->kw;
93 : 0 : func = part->fn;
94 : : assert(PyTuple_Check(pargs));
95 : : assert(PyDict_Check(pkw));
96 : : }
97 : : }
98 [ - + ]: 78 : if (!PyCallable_Check(func)) {
99 : 0 : PyErr_SetString(PyExc_TypeError,
100 : : "the first argument must be callable");
101 : 0 : return NULL;
102 : : }
103 : :
104 : : /* create partialobject structure */
105 : 78 : pto = (partialobject *)type->tp_alloc(type, 0);
106 [ - + ]: 78 : if (pto == NULL)
107 : 0 : return NULL;
108 : :
109 : 78 : pto->fn = Py_NewRef(func);
110 : :
111 : 78 : nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
112 [ - + ]: 78 : if (nargs == NULL) {
113 : 0 : Py_DECREF(pto);
114 : 0 : return NULL;
115 : : }
116 [ + - ]: 78 : if (pargs == NULL) {
117 : 78 : pto->args = nargs;
118 : : }
119 : : else {
120 : 0 : pto->args = PySequence_Concat(pargs, nargs);
121 : 0 : Py_DECREF(nargs);
122 [ # # ]: 0 : if (pto->args == NULL) {
123 : 0 : Py_DECREF(pto);
124 : 0 : return NULL;
125 : : }
126 : : assert(PyTuple_Check(pto->args));
127 : : }
128 : :
129 [ - + - - ]: 78 : if (pkw == NULL || PyDict_GET_SIZE(pkw) == 0) {
130 [ + + ]: 78 : if (kw == NULL) {
131 : 5 : pto->kw = PyDict_New();
132 : : }
133 [ + - ]: 73 : else if (Py_REFCNT(kw) == 1) {
134 : 73 : pto->kw = Py_NewRef(kw);
135 : : }
136 : : else {
137 : 0 : pto->kw = PyDict_Copy(kw);
138 : : }
139 : : }
140 : : else {
141 : 0 : pto->kw = PyDict_Copy(pkw);
142 [ # # # # ]: 0 : if (kw != NULL && pto->kw != NULL) {
143 [ # # ]: 0 : if (PyDict_Merge(pto->kw, kw, 1) != 0) {
144 : 0 : Py_DECREF(pto);
145 : 0 : return NULL;
146 : : }
147 : : }
148 : : }
149 [ - + ]: 78 : if (pto->kw == NULL) {
150 : 0 : Py_DECREF(pto);
151 : 0 : return NULL;
152 : : }
153 : :
154 : 78 : partial_setvectorcall(pto);
155 : 78 : return (PyObject *)pto;
156 : : }
157 : :
158 : : static int
159 : 78 : partial_clear(partialobject *pto)
160 : : {
161 [ + - ]: 78 : Py_CLEAR(pto->fn);
162 [ + - ]: 78 : Py_CLEAR(pto->args);
163 [ + - ]: 78 : Py_CLEAR(pto->kw);
164 [ - + ]: 78 : Py_CLEAR(pto->dict);
165 : 78 : return 0;
166 : : }
167 : :
168 : : static int
169 : 56 : partial_traverse(partialobject *pto, visitproc visit, void *arg)
170 : : {
171 [ + - - + ]: 56 : Py_VISIT(Py_TYPE(pto));
172 [ + - - + ]: 56 : Py_VISIT(pto->fn);
173 [ + - - + ]: 56 : Py_VISIT(pto->args);
174 [ + - - + ]: 56 : Py_VISIT(pto->kw);
175 [ - + - - ]: 56 : Py_VISIT(pto->dict);
176 : 56 : return 0;
177 : : }
178 : :
179 : : static void
180 : 78 : partial_dealloc(partialobject *pto)
181 : : {
182 : 78 : PyTypeObject *tp = Py_TYPE(pto);
183 : : /* bpo-31095: UnTrack is needed before calling any callbacks */
184 : 78 : PyObject_GC_UnTrack(pto);
185 [ - + ]: 78 : if (pto->weakreflist != NULL) {
186 : 0 : PyObject_ClearWeakRefs((PyObject *) pto);
187 : : }
188 : 78 : (void)partial_clear(pto);
189 : 78 : tp->tp_free(pto);
190 : 78 : Py_DECREF(tp);
191 : 78 : }
192 : :
193 : :
194 : : /* Merging keyword arguments using the vectorcall convention is messy, so
195 : : * if we would need to do that, we stop using vectorcall and fall back
196 : : * to using partial_call() instead. */
197 : : Py_NO_INLINE static PyObject *
198 : 72 : partial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto,
199 : : PyObject *const *args, size_t nargsf,
200 : : PyObject *kwnames)
201 : : {
202 : 72 : pto->vectorcall = NULL;
203 : 72 : Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
204 : 72 : return _PyObject_MakeTpCall(tstate, (PyObject *)pto,
205 : : args, nargs, kwnames);
206 : : }
207 : :
208 : : static PyObject *
209 : 73 : partial_vectorcall(partialobject *pto, PyObject *const *args,
210 : : size_t nargsf, PyObject *kwnames)
211 : : {
212 : 73 : PyThreadState *tstate = _PyThreadState_GET();
213 : :
214 : : /* pto->kw is mutable, so need to check every time */
215 [ + + ]: 73 : if (PyDict_GET_SIZE(pto->kw)) {
216 : 72 : return partial_vectorcall_fallback(tstate, pto, args, nargsf, kwnames);
217 : : }
218 : :
219 : 1 : Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
220 : 1 : Py_ssize_t nargs_total = nargs;
221 [ - + ]: 1 : if (kwnames != NULL) {
222 : 0 : nargs_total += PyTuple_GET_SIZE(kwnames);
223 : : }
224 : :
225 : 1 : PyObject **pto_args = _PyTuple_ITEMS(pto->args);
226 : 1 : Py_ssize_t pto_nargs = PyTuple_GET_SIZE(pto->args);
227 : :
228 : : /* Fast path if we're called without arguments */
229 [ + - ]: 1 : if (nargs_total == 0) {
230 : 1 : return _PyObject_VectorcallTstate(tstate, pto->fn,
231 : : pto_args, pto_nargs, NULL);
232 : : }
233 : :
234 : : /* Fast path using PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
235 : : * positional argument */
236 [ # # # # ]: 0 : if (pto_nargs == 1 && (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET)) {
237 : 0 : PyObject **newargs = (PyObject **)args - 1;
238 : 0 : PyObject *tmp = newargs[0];
239 : 0 : newargs[0] = pto_args[0];
240 : 0 : PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn,
241 : 0 : newargs, nargs + 1, kwnames);
242 : 0 : newargs[0] = tmp;
243 : 0 : return ret;
244 : : }
245 : :
246 : 0 : Py_ssize_t newnargs_total = pto_nargs + nargs_total;
247 : :
248 : : PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
249 : : PyObject *ret;
250 : : PyObject **stack;
251 : :
252 [ # # ]: 0 : if (newnargs_total <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
253 : 0 : stack = small_stack;
254 : : }
255 : : else {
256 : 0 : stack = PyMem_Malloc(newnargs_total * sizeof(PyObject *));
257 [ # # ]: 0 : if (stack == NULL) {
258 : 0 : PyErr_NoMemory();
259 : 0 : return NULL;
260 : : }
261 : : }
262 : :
263 : : /* Copy to new stack, using borrowed references */
264 : 0 : memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
265 : 0 : memcpy(stack + pto_nargs, args, nargs_total * sizeof(PyObject*));
266 : :
267 : 0 : ret = _PyObject_VectorcallTstate(tstate, pto->fn,
268 : 0 : stack, pto_nargs + nargs, kwnames);
269 [ # # ]: 0 : if (stack != small_stack) {
270 : 0 : PyMem_Free(stack);
271 : : }
272 : 0 : return ret;
273 : : }
274 : :
275 : : /* Set pto->vectorcall depending on the parameters of the partial object */
276 : : static void
277 : 78 : partial_setvectorcall(partialobject *pto)
278 : : {
279 [ + + ]: 78 : if (_PyVectorcall_Function(pto->fn) == NULL) {
280 : : /* Don't use vectorcall if the underlying function doesn't support it */
281 : 4 : pto->vectorcall = NULL;
282 : : }
283 : : /* We could have a special case if there are no arguments,
284 : : * but that is unlikely (why use partial without arguments?),
285 : : * so we don't optimize that */
286 : : else {
287 : 74 : pto->vectorcall = (vectorcallfunc)partial_vectorcall;
288 : : }
289 : 78 : }
290 : :
291 : :
292 : : // Not converted to argument clinic, because of `*args, **kwargs` arguments.
293 : : static PyObject *
294 : 73 : partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
295 : : {
296 : : assert(PyCallable_Check(pto->fn));
297 : : assert(PyTuple_Check(pto->args));
298 : : assert(PyDict_Check(pto->kw));
299 : :
300 : : /* Merge keywords */
301 : : PyObject *kwargs2;
302 [ - + ]: 73 : if (PyDict_GET_SIZE(pto->kw) == 0) {
303 : : /* kwargs can be NULL */
304 : 0 : kwargs2 = Py_XNewRef(kwargs);
305 : : }
306 : : else {
307 : : /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
308 : : copied, because a function using "**kwargs" can modify the
309 : : dictionary. */
310 : 73 : kwargs2 = PyDict_Copy(pto->kw);
311 [ - + ]: 73 : if (kwargs2 == NULL) {
312 : 0 : return NULL;
313 : : }
314 : :
315 [ - + ]: 73 : if (kwargs != NULL) {
316 [ # # ]: 0 : if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
317 : 0 : Py_DECREF(kwargs2);
318 : 0 : return NULL;
319 : : }
320 : : }
321 : : }
322 : :
323 : : /* Merge positional arguments */
324 : : /* Note: tupleconcat() is optimized for empty tuples */
325 : 73 : PyObject *args2 = PySequence_Concat(pto->args, args);
326 [ - + ]: 73 : if (args2 == NULL) {
327 : 0 : Py_XDECREF(kwargs2);
328 : 0 : return NULL;
329 : : }
330 : :
331 : 73 : PyObject *res = PyObject_Call(pto->fn, args2, kwargs2);
332 : 73 : Py_DECREF(args2);
333 : 73 : Py_XDECREF(kwargs2);
334 : 73 : return res;
335 : : }
336 : :
337 : : PyDoc_STRVAR(partial_doc,
338 : : "partial(func, *args, **keywords) - new function with partial application\n\
339 : : of the given arguments and keywords.\n");
340 : :
341 : : #define OFF(x) offsetof(partialobject, x)
342 : : static PyMemberDef partial_memberlist[] = {
343 : : {"func", T_OBJECT, OFF(fn), READONLY,
344 : : "function object to use in future partial calls"},
345 : : {"args", T_OBJECT, OFF(args), READONLY,
346 : : "tuple of arguments to future partial calls"},
347 : : {"keywords", T_OBJECT, OFF(kw), READONLY,
348 : : "dictionary of keyword arguments to future partial calls"},
349 : : {"__weaklistoffset__", T_PYSSIZET,
350 : : offsetof(partialobject, weakreflist), READONLY},
351 : : {"__dictoffset__", T_PYSSIZET,
352 : : offsetof(partialobject, dict), READONLY},
353 : : {"__vectorcalloffset__", T_PYSSIZET,
354 : : offsetof(partialobject, vectorcall), READONLY},
355 : : {NULL} /* Sentinel */
356 : : };
357 : :
358 : : static PyGetSetDef partial_getsetlist[] = {
359 : : {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
360 : : {NULL} /* Sentinel */
361 : : };
362 : :
363 : : static PyObject *
364 : 0 : partial_repr(partialobject *pto)
365 : : {
366 : 0 : PyObject *result = NULL;
367 : : PyObject *arglist;
368 : : Py_ssize_t i, n;
369 : : PyObject *key, *value;
370 : : int status;
371 : :
372 : 0 : status = Py_ReprEnter((PyObject *)pto);
373 [ # # ]: 0 : if (status != 0) {
374 [ # # ]: 0 : if (status < 0)
375 : 0 : return NULL;
376 : 0 : return PyUnicode_FromString("...");
377 : : }
378 : :
379 : 0 : arglist = PyUnicode_FromString("");
380 [ # # ]: 0 : if (arglist == NULL)
381 : 0 : goto done;
382 : : /* Pack positional arguments */
383 : : assert (PyTuple_Check(pto->args));
384 : 0 : n = PyTuple_GET_SIZE(pto->args);
385 [ # # ]: 0 : for (i = 0; i < n; i++) {
386 : 0 : Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
387 : : PyTuple_GET_ITEM(pto->args, i)));
388 [ # # ]: 0 : if (arglist == NULL)
389 : 0 : goto done;
390 : : }
391 : : /* Pack keyword arguments */
392 : : assert (PyDict_Check(pto->kw));
393 [ # # ]: 0 : for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
394 : : /* Prevent key.__str__ from deleting the value. */
395 : 0 : Py_INCREF(value);
396 : 0 : Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
397 : : key, value));
398 : 0 : Py_DECREF(value);
399 [ # # ]: 0 : if (arglist == NULL)
400 : 0 : goto done;
401 : : }
402 : 0 : result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
403 : : pto->fn, arglist);
404 : 0 : Py_DECREF(arglist);
405 : :
406 : 0 : done:
407 : 0 : Py_ReprLeave((PyObject *)pto);
408 : 0 : return result;
409 : : }
410 : :
411 : : /* Pickle strategy:
412 : : __reduce__ by itself doesn't support getting kwargs in the unpickle
413 : : operation so we define a __setstate__ that replaces all the information
414 : : about the partial. If we only replaced part of it someone would use
415 : : it as a hook to do strange things.
416 : : */
417 : :
418 : : static PyObject *
419 : 0 : partial_reduce(partialobject *pto, PyObject *unused)
420 : : {
421 : 0 : return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
422 : : pto->args, pto->kw,
423 [ # # ]: 0 : pto->dict ? pto->dict : Py_None);
424 : : }
425 : :
426 : : static PyObject *
427 : 0 : partial_setstate(partialobject *pto, PyObject *state)
428 : : {
429 : : PyObject *fn, *fnargs, *kw, *dict;
430 : :
431 [ # # # # ]: 0 : if (!PyTuple_Check(state) ||
432 [ # # ]: 0 : !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
433 [ # # ]: 0 : !PyCallable_Check(fn) ||
434 : 0 : !PyTuple_Check(fnargs) ||
435 [ # # # # ]: 0 : (kw != Py_None && !PyDict_Check(kw)))
436 : : {
437 : 0 : PyErr_SetString(PyExc_TypeError, "invalid partial state");
438 : 0 : return NULL;
439 : : }
440 : :
441 [ # # ]: 0 : if(!PyTuple_CheckExact(fnargs))
442 : 0 : fnargs = PySequence_Tuple(fnargs);
443 : : else
444 : 0 : Py_INCREF(fnargs);
445 [ # # ]: 0 : if (fnargs == NULL)
446 : 0 : return NULL;
447 : :
448 [ # # ]: 0 : if (kw == Py_None)
449 : 0 : kw = PyDict_New();
450 [ # # ]: 0 : else if(!PyDict_CheckExact(kw))
451 : 0 : kw = PyDict_Copy(kw);
452 : : else
453 : 0 : Py_INCREF(kw);
454 [ # # ]: 0 : if (kw == NULL) {
455 : 0 : Py_DECREF(fnargs);
456 : 0 : return NULL;
457 : : }
458 : :
459 [ # # ]: 0 : if (dict == Py_None)
460 : 0 : dict = NULL;
461 : : else
462 : 0 : Py_INCREF(dict);
463 : :
464 : 0 : Py_SETREF(pto->fn, Py_NewRef(fn));
465 : 0 : Py_SETREF(pto->args, fnargs);
466 : 0 : Py_SETREF(pto->kw, kw);
467 : 0 : Py_XSETREF(pto->dict, dict);
468 : 0 : partial_setvectorcall(pto);
469 : 0 : Py_RETURN_NONE;
470 : : }
471 : :
472 : : static PyMethodDef partial_methods[] = {
473 : : {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
474 : : {"__setstate__", (PyCFunction)partial_setstate, METH_O},
475 : : {"__class_getitem__", Py_GenericAlias,
476 : : METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
477 : : {NULL, NULL} /* sentinel */
478 : : };
479 : :
480 : : static PyType_Slot partial_type_slots[] = {
481 : : {Py_tp_dealloc, partial_dealloc},
482 : : {Py_tp_repr, partial_repr},
483 : : {Py_tp_call, partial_call},
484 : : {Py_tp_getattro, PyObject_GenericGetAttr},
485 : : {Py_tp_setattro, PyObject_GenericSetAttr},
486 : : {Py_tp_doc, (void *)partial_doc},
487 : : {Py_tp_traverse, partial_traverse},
488 : : {Py_tp_clear, partial_clear},
489 : : {Py_tp_methods, partial_methods},
490 : : {Py_tp_members, partial_memberlist},
491 : : {Py_tp_getset, partial_getsetlist},
492 : : {Py_tp_new, partial_new},
493 : : {Py_tp_free, PyObject_GC_Del},
494 : : {0, 0}
495 : : };
496 : :
497 : : static PyType_Spec partial_type_spec = {
498 : : .name = "functools.partial",
499 : : .basicsize = sizeof(partialobject),
500 : : .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
501 : : Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL |
502 : : Py_TPFLAGS_IMMUTABLETYPE,
503 : : .slots = partial_type_slots
504 : : };
505 : :
506 : :
507 : : /* cmp_to_key ***************************************************************/
508 : :
509 : : typedef struct {
510 : : PyObject_HEAD
511 : : PyObject *cmp;
512 : : PyObject *object;
513 : : } keyobject;
514 : :
515 : : static int
516 : 79 : keyobject_clear(keyobject *ko)
517 : : {
518 [ + - ]: 79 : Py_CLEAR(ko->cmp);
519 [ + + ]: 79 : Py_CLEAR(ko->object);
520 : 79 : return 0;
521 : : }
522 : :
523 : : static void
524 : 79 : keyobject_dealloc(keyobject *ko)
525 : : {
526 : 79 : PyTypeObject *tp = Py_TYPE(ko);
527 : 79 : PyObject_GC_UnTrack(ko);
528 : 79 : (void)keyobject_clear(ko);
529 : 79 : tp->tp_free(ko);
530 : 79 : Py_DECREF(tp);
531 : 79 : }
532 : :
533 : : static int
534 : 0 : keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
535 : : {
536 [ # # # # ]: 0 : Py_VISIT(Py_TYPE(ko));
537 [ # # # # ]: 0 : Py_VISIT(ko->cmp);
538 [ # # # # ]: 0 : Py_VISIT(ko->object);
539 : 0 : return 0;
540 : : }
541 : :
542 : : static PyMemberDef keyobject_members[] = {
543 : : {"obj", T_OBJECT,
544 : : offsetof(keyobject, object), 0,
545 : : PyDoc_STR("Value wrapped by a key function.")},
546 : : {NULL}
547 : : };
548 : :
549 : : static PyObject *
550 : : keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
551 : :
552 : : static PyObject *
553 : : keyobject_richcompare(PyObject *ko, PyObject *other, int op);
554 : :
555 : : static PyType_Slot keyobject_type_slots[] = {
556 : : {Py_tp_dealloc, keyobject_dealloc},
557 : : {Py_tp_call, keyobject_call},
558 : : {Py_tp_getattro, PyObject_GenericGetAttr},
559 : : {Py_tp_traverse, keyobject_traverse},
560 : : {Py_tp_clear, keyobject_clear},
561 : : {Py_tp_richcompare, keyobject_richcompare},
562 : : {Py_tp_members, keyobject_members},
563 : : {0, 0}
564 : : };
565 : :
566 : : static PyType_Spec keyobject_type_spec = {
567 : : .name = "functools.KeyWrapper",
568 : : .basicsize = sizeof(keyobject),
569 : : .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
570 : : Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
571 : : .slots = keyobject_type_slots
572 : : };
573 : :
574 : : static PyObject *
575 : 77 : keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
576 : : {
577 : : PyObject *object;
578 : : keyobject *result;
579 : : static char *kwargs[] = {"obj", NULL};
580 : :
581 [ - + ]: 77 : if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
582 : 0 : return NULL;
583 : :
584 : 77 : result = PyObject_GC_New(keyobject, Py_TYPE(ko));
585 [ - + ]: 77 : if (result == NULL) {
586 : 0 : return NULL;
587 : : }
588 : 77 : result->cmp = Py_NewRef(ko->cmp);
589 : 77 : result->object = Py_NewRef(object);
590 : 77 : PyObject_GC_Track(result);
591 : 77 : return (PyObject *)result;
592 : : }
593 : :
594 : : static PyObject *
595 : 75 : keyobject_richcompare(PyObject *ko, PyObject *other, int op)
596 : : {
597 : : PyObject *res;
598 : : PyObject *x;
599 : : PyObject *y;
600 : : PyObject *compare;
601 : : PyObject *answer;
602 : : PyObject* stack[2];
603 : :
604 [ - + ]: 75 : if (!Py_IS_TYPE(other, Py_TYPE(ko))) {
605 : 0 : PyErr_Format(PyExc_TypeError, "other argument must be K instance");
606 : 0 : return NULL;
607 : : }
608 : 75 : compare = ((keyobject *) ko)->cmp;
609 : : assert(compare != NULL);
610 : 75 : x = ((keyobject *) ko)->object;
611 : 75 : y = ((keyobject *) other)->object;
612 [ + - - + ]: 75 : if (!x || !y){
613 : 0 : PyErr_Format(PyExc_AttributeError, "object");
614 : 0 : return NULL;
615 : : }
616 : :
617 : : /* Call the user's comparison function and translate the 3-way
618 : : * result into true or false (or error).
619 : : */
620 : 75 : stack[0] = x;
621 : 75 : stack[1] = y;
622 : 75 : res = _PyObject_FastCall(compare, stack, 2);
623 [ - + ]: 75 : if (res == NULL) {
624 : 0 : return NULL;
625 : : }
626 : :
627 : 75 : answer = PyObject_RichCompare(res, _PyLong_GetZero(), op);
628 : 75 : Py_DECREF(res);
629 : 75 : return answer;
630 : : }
631 : :
632 : : /*[clinic input]
633 : : _functools.cmp_to_key
634 : :
635 : : mycmp: object
636 : : Function that compares two objects.
637 : :
638 : : Convert a cmp= function into a key= function.
639 : : [clinic start generated code]*/
640 : :
641 : : static PyObject *
642 : 2 : _functools_cmp_to_key_impl(PyObject *module, PyObject *mycmp)
643 : : /*[clinic end generated code: output=71eaad0f4fc81f33 input=d1b76f231c0dfeb3]*/
644 : : {
645 : : keyobject *object;
646 : : _functools_state *state;
647 : :
648 : 2 : state = get_functools_state(module);
649 : 2 : object = PyObject_GC_New(keyobject, state->keyobject_type);
650 [ - + ]: 2 : if (!object)
651 : 0 : return NULL;
652 : 2 : object->cmp = Py_NewRef(mycmp);
653 : 2 : object->object = NULL;
654 : 2 : PyObject_GC_Track(object);
655 : 2 : return (PyObject *)object;
656 : : }
657 : :
658 : : /* reduce (used to be a builtin) ********************************************/
659 : :
660 : : // Not converted to argument clinic, because of `args` in-place modification.
661 : : // AC will affect performance.
662 : : static PyObject *
663 : 0 : functools_reduce(PyObject *self, PyObject *args)
664 : : {
665 : 0 : PyObject *seq, *func, *result = NULL, *it;
666 : :
667 [ # # ]: 0 : if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
668 : 0 : return NULL;
669 [ # # ]: 0 : if (result != NULL)
670 : 0 : Py_INCREF(result);
671 : :
672 : 0 : it = PyObject_GetIter(seq);
673 [ # # ]: 0 : if (it == NULL) {
674 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_TypeError))
675 : 0 : PyErr_SetString(PyExc_TypeError,
676 : : "reduce() arg 2 must support iteration");
677 : 0 : Py_XDECREF(result);
678 : 0 : return NULL;
679 : : }
680 : :
681 [ # # ]: 0 : if ((args = PyTuple_New(2)) == NULL)
682 : 0 : goto Fail;
683 : :
684 : 0 : for (;;) {
685 : : PyObject *op2;
686 : :
687 [ # # ]: 0 : if (Py_REFCNT(args) > 1) {
688 : 0 : Py_DECREF(args);
689 [ # # ]: 0 : if ((args = PyTuple_New(2)) == NULL)
690 : 0 : goto Fail;
691 : : }
692 : :
693 : 0 : op2 = PyIter_Next(it);
694 [ # # ]: 0 : if (op2 == NULL) {
695 [ # # ]: 0 : if (PyErr_Occurred())
696 : 0 : goto Fail;
697 : 0 : break;
698 : : }
699 : :
700 [ # # ]: 0 : if (result == NULL)
701 : 0 : result = op2;
702 : : else {
703 : : /* Update the args tuple in-place */
704 : : assert(Py_REFCNT(args) == 1);
705 : 0 : Py_XSETREF(_PyTuple_ITEMS(args)[0], result);
706 : 0 : Py_XSETREF(_PyTuple_ITEMS(args)[1], op2);
707 [ # # ]: 0 : if ((result = PyObject_Call(func, args, NULL)) == NULL) {
708 : 0 : goto Fail;
709 : : }
710 : : // bpo-42536: The GC may have untracked this args tuple. Since we're
711 : : // recycling it, make sure it's tracked again:
712 [ # # ]: 0 : if (!_PyObject_GC_IS_TRACKED(args)) {
713 : 0 : _PyObject_GC_TRACK(args);
714 : : }
715 : : }
716 : : }
717 : :
718 : 0 : Py_DECREF(args);
719 : :
720 [ # # ]: 0 : if (result == NULL)
721 : 0 : PyErr_SetString(PyExc_TypeError,
722 : : "reduce() of empty iterable with no initial value");
723 : :
724 : 0 : Py_DECREF(it);
725 : 0 : return result;
726 : :
727 : 0 : Fail:
728 : 0 : Py_XDECREF(args);
729 : 0 : Py_XDECREF(result);
730 : 0 : Py_DECREF(it);
731 : 0 : return NULL;
732 : : }
733 : :
734 : : PyDoc_STRVAR(functools_reduce_doc,
735 : : "reduce(function, iterable[, initial]) -> value\n\
736 : : \n\
737 : : Apply a function of two arguments cumulatively to the items of a sequence\n\
738 : : or iterable, from left to right, so as to reduce the iterable to a single\n\
739 : : value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
740 : : ((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
741 : : of the iterable in the calculation, and serves as a default when the\n\
742 : : iterable is empty.");
743 : :
744 : : /* lru_cache object **********************************************************/
745 : :
746 : : /* There are four principal algorithmic differences from the pure python version:
747 : :
748 : : 1). The C version relies on the GIL instead of having its own reentrant lock.
749 : :
750 : : 2). The prev/next link fields use borrowed references.
751 : :
752 : : 3). For a full cache, the pure python version rotates the location of the
753 : : root entry so that it never has to move individual links and it can
754 : : limit updates to just the key and result fields. However, in the C
755 : : version, links are temporarily removed while the cache dict updates are
756 : : occurring. Afterwards, they are appended or prepended back into the
757 : : doubly-linked lists.
758 : :
759 : : 4) In the Python version, the _HashSeq class is used to prevent __hash__
760 : : from being called more than once. In the C version, the "known hash"
761 : : variants of dictionary calls as used to the same effect.
762 : :
763 : : */
764 : :
765 : : struct lru_list_elem;
766 : : struct lru_cache_object;
767 : :
768 : : typedef struct lru_list_elem {
769 : : PyObject_HEAD
770 : : struct lru_list_elem *prev, *next; /* borrowed links */
771 : : Py_hash_t hash;
772 : : PyObject *key, *result;
773 : : } lru_list_elem;
774 : :
775 : : static void
776 : 61 : lru_list_elem_dealloc(lru_list_elem *link)
777 : : {
778 : 61 : PyTypeObject *tp = Py_TYPE(link);
779 : 61 : Py_XDECREF(link->key);
780 : 61 : Py_XDECREF(link->result);
781 : 61 : tp->tp_free(link);
782 : 61 : Py_DECREF(tp);
783 : 61 : }
784 : :
785 : : static PyType_Slot lru_list_elem_type_slots[] = {
786 : : {Py_tp_dealloc, lru_list_elem_dealloc},
787 : : {0, 0}
788 : : };
789 : :
790 : : static PyType_Spec lru_list_elem_type_spec = {
791 : : .name = "functools._lru_list_elem",
792 : : .basicsize = sizeof(lru_list_elem),
793 : : .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
794 : : Py_TPFLAGS_IMMUTABLETYPE,
795 : : .slots = lru_list_elem_type_slots
796 : : };
797 : :
798 : :
799 : : typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
800 : :
801 : : typedef struct lru_cache_object {
802 : : lru_list_elem root; /* includes PyObject_HEAD */
803 : : lru_cache_ternaryfunc wrapper;
804 : : int typed;
805 : : PyObject *cache;
806 : : Py_ssize_t hits;
807 : : PyObject *func;
808 : : Py_ssize_t maxsize;
809 : : Py_ssize_t misses;
810 : : /* the kwd_mark is used delimit args and keywords in the cache keys */
811 : : PyObject *kwd_mark;
812 : : PyTypeObject *lru_list_elem_type;
813 : : PyObject *cache_info_type;
814 : : PyObject *dict;
815 : : PyObject *weakreflist;
816 : : } lru_cache_object;
817 : :
818 : : static PyObject *
819 : 81 : lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
820 : : PyObject *kwds, int typed)
821 : : {
822 : : PyObject *key, *keyword, *value;
823 : : Py_ssize_t key_size, pos, key_pos, kwds_size;
824 : :
825 [ + - ]: 81 : kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
826 : :
827 : : /* short path, key will match args anyway, which is a tuple */
828 [ + - + - ]: 81 : if (!typed && !kwds_size) {
829 [ - + ]: 81 : if (PyTuple_GET_SIZE(args) == 1) {
830 : 0 : key = PyTuple_GET_ITEM(args, 0);
831 [ # # # # ]: 0 : if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) {
832 : : /* For common scalar keys, save space by
833 : : dropping the enclosing args tuple */
834 : 0 : return Py_NewRef(key);
835 : : }
836 : : }
837 : 81 : return Py_NewRef(args);
838 : : }
839 : :
840 : 0 : key_size = PyTuple_GET_SIZE(args);
841 [ # # ]: 0 : if (kwds_size)
842 : 0 : key_size += kwds_size * 2 + 1;
843 [ # # ]: 0 : if (typed)
844 : 0 : key_size += PyTuple_GET_SIZE(args) + kwds_size;
845 : :
846 : 0 : key = PyTuple_New(key_size);
847 [ # # ]: 0 : if (key == NULL)
848 : 0 : return NULL;
849 : :
850 : 0 : key_pos = 0;
851 [ # # ]: 0 : for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
852 : 0 : PyObject *item = PyTuple_GET_ITEM(args, pos);
853 : 0 : PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
854 : : }
855 [ # # ]: 0 : if (kwds_size) {
856 : 0 : PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(kwd_mark));
857 [ # # ]: 0 : for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
858 : 0 : PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(keyword));
859 : 0 : PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(value));
860 : : }
861 : : assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
862 : : }
863 [ # # ]: 0 : if (typed) {
864 [ # # ]: 0 : for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
865 : 0 : PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
866 : 0 : PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
867 : : }
868 [ # # ]: 0 : if (kwds_size) {
869 [ # # ]: 0 : for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
870 : 0 : PyObject *item = (PyObject *)Py_TYPE(value);
871 : 0 : PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
872 : : }
873 : : }
874 : : }
875 : : assert(key_pos == key_size);
876 : 0 : return key;
877 : : }
878 : :
879 : : static PyObject *
880 : 0 : uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
881 : : {
882 : : PyObject *result;
883 : :
884 : 0 : self->misses++;
885 : 0 : result = PyObject_Call(self->func, args, kwds);
886 [ # # ]: 0 : if (!result)
887 : 0 : return NULL;
888 : 0 : return result;
889 : : }
890 : :
891 : : static PyObject *
892 : 0 : infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
893 : : {
894 : : PyObject *result;
895 : : Py_hash_t hash;
896 : 0 : PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
897 [ # # ]: 0 : if (!key)
898 : 0 : return NULL;
899 : 0 : hash = PyObject_Hash(key);
900 [ # # ]: 0 : if (hash == -1) {
901 : 0 : Py_DECREF(key);
902 : 0 : return NULL;
903 : : }
904 : 0 : result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
905 [ # # ]: 0 : if (result) {
906 : 0 : Py_INCREF(result);
907 : 0 : self->hits++;
908 : 0 : Py_DECREF(key);
909 : 0 : return result;
910 : : }
911 [ # # ]: 0 : if (PyErr_Occurred()) {
912 : 0 : Py_DECREF(key);
913 : 0 : return NULL;
914 : : }
915 : 0 : self->misses++;
916 : 0 : result = PyObject_Call(self->func, args, kwds);
917 [ # # ]: 0 : if (!result) {
918 : 0 : Py_DECREF(key);
919 : 0 : return NULL;
920 : : }
921 [ # # ]: 0 : if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
922 : 0 : Py_DECREF(result);
923 : 0 : Py_DECREF(key);
924 : 0 : return NULL;
925 : : }
926 : 0 : Py_DECREF(key);
927 : 0 : return result;
928 : : }
929 : :
930 : : static void
931 : 20 : lru_cache_extract_link(lru_list_elem *link)
932 : : {
933 : 20 : lru_list_elem *link_prev = link->prev;
934 : 20 : lru_list_elem *link_next = link->next;
935 : 20 : link_prev->next = link->next;
936 : 20 : link_next->prev = link->prev;
937 : 20 : }
938 : :
939 : : static void
940 : 81 : lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
941 : : {
942 : 81 : lru_list_elem *root = &self->root;
943 : 81 : lru_list_elem *last = root->prev;
944 : 81 : last->next = root->prev = link;
945 : 81 : link->prev = last;
946 : 81 : link->next = root;
947 : 81 : }
948 : :
949 : : static void
950 : 0 : lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
951 : : {
952 : 0 : lru_list_elem *root = &self->root;
953 : 0 : lru_list_elem *first = root->next;
954 : 0 : first->prev = root->next = link;
955 : 0 : link->prev = root;
956 : 0 : link->next = first;
957 : 0 : }
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 : :
990 : : static PyObject *
991 : 81 : bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
992 : : {
993 : : lru_list_elem *link;
994 : : PyObject *key, *result, *testresult;
995 : : Py_hash_t hash;
996 : :
997 : 81 : key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
998 [ - + ]: 81 : if (!key)
999 : 0 : return NULL;
1000 : 81 : hash = PyObject_Hash(key);
1001 [ - + ]: 81 : if (hash == -1) {
1002 : 0 : Py_DECREF(key);
1003 : 0 : return NULL;
1004 : : }
1005 : 81 : link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
1006 [ + + ]: 81 : if (link != NULL) {
1007 : 20 : lru_cache_extract_link(link);
1008 : 20 : lru_cache_append_link(self, link);
1009 : 20 : result = link->result;
1010 : 20 : self->hits++;
1011 : 20 : Py_INCREF(result);
1012 : 20 : Py_DECREF(key);
1013 : 20 : return result;
1014 : : }
1015 [ - + ]: 61 : if (PyErr_Occurred()) {
1016 : 0 : Py_DECREF(key);
1017 : 0 : return NULL;
1018 : : }
1019 : 61 : self->misses++;
1020 : 61 : result = PyObject_Call(self->func, args, kwds);
1021 [ - + ]: 61 : if (!result) {
1022 : 0 : Py_DECREF(key);
1023 : 0 : return NULL;
1024 : : }
1025 : 61 : testresult = _PyDict_GetItem_KnownHash(self->cache, key, hash);
1026 [ - + ]: 61 : 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 : 0 : Py_DECREF(key);
1031 : 0 : return result;
1032 : : }
1033 [ - + ]: 61 : 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 : 0 : Py_DECREF(key);
1039 : 0 : Py_DECREF(result);
1040 : 0 : 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. */
1045 : :
1046 : : assert(self->maxsize > 0);
1047 [ - + ]: 61 : if (PyDict_GET_SIZE(self->cache) < self->maxsize ||
1048 [ # # ]: 0 : self->root.next == &self->root)
1049 : : {
1050 : : /* Cache is not full, so put the result in a new link */
1051 : 61 : link = (lru_list_elem *)PyObject_New(lru_list_elem,
1052 : : self->lru_list_elem_type);
1053 [ - + ]: 61 : if (link == NULL) {
1054 : 0 : Py_DECREF(key);
1055 : 0 : Py_DECREF(result);
1056 : 0 : return NULL;
1057 : : }
1058 : :
1059 : 61 : link->hash = hash;
1060 : 61 : link->key = key;
1061 : 61 : link->result = result;
1062 : : /* 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). */
1067 [ - + ]: 61 : if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
1068 : : hash) < 0) {
1069 : 0 : Py_DECREF(link);
1070 : 0 : return NULL;
1071 : : }
1072 : 61 : lru_cache_append_link(self, link);
1073 : 61 : return Py_NewRef(result);
1074 : : }
1075 : : /* Since the cache is full, we need to evict an old key and add
1076 : : a new key. Rather than free the old link and allocate a new
1077 : : one, we reuse the link for the new key and result and move it
1078 : : to front of the cache to mark it as recently used.
1079 : :
1080 : : We try to assure all code paths (including errors) leave all
1081 : : of the links in place. Either the link is successfully
1082 : : updated and moved or it is restored to its old position.
1083 : : However if an unrecoverable error is found, it doesn't
1084 : : make sense to reinsert the link, so we leave it out
1085 : : and the cache will no longer register as full.
1086 : : */
1087 : : PyObject *oldkey, *oldresult, *popresult;
1088 : :
1089 : : /* Extract the oldest item. */
1090 : : assert(self->root.next != &self->root);
1091 : 0 : link = self->root.next;
1092 : 0 : lru_cache_extract_link(link);
1093 : : /* Remove it from the cache.
1094 : : The cache dict holds one reference to the link.
1095 : : We created one other reference when the link was created.
1096 : : The linked list only has borrowed references. */
1097 : 0 : popresult = _PyDict_Pop_KnownHash(self->cache, link->key,
1098 : : link->hash, Py_None);
1099 [ # # ]: 0 : if (popresult == Py_None) {
1100 : : /* Getting here means that the user function call or another
1101 : : thread has already removed the old key from the dictionary.
1102 : : This link is now an orphan. Since we don't want to leave the
1103 : : cache in an inconsistent state, we don't restore the link. */
1104 : 0 : Py_DECREF(popresult);
1105 : 0 : Py_DECREF(link);
1106 : 0 : Py_DECREF(key);
1107 : 0 : return result;
1108 : : }
1109 [ # # ]: 0 : if (popresult == NULL) {
1110 : : /* An error arose while trying to remove the oldest key (the one
1111 : : being evicted) from the cache. We restore the link to its
1112 : : original position as the oldest link. Then we allow the
1113 : : error propagate upward; treating it the same as an error
1114 : : arising in the user function. */
1115 : 0 : lru_cache_prepend_link(self, link);
1116 : 0 : Py_DECREF(key);
1117 : 0 : Py_DECREF(result);
1118 : 0 : return NULL;
1119 : : }
1120 : : /* Keep a reference to the old key and old result to prevent their
1121 : : ref counts from going to zero during the update. That will
1122 : : prevent potentially arbitrary object clean-up code (i.e. __del__)
1123 : : from running while we're still adjusting the links. */
1124 : 0 : oldkey = link->key;
1125 : 0 : oldresult = link->result;
1126 : :
1127 : 0 : link->hash = hash;
1128 : 0 : link->key = key;
1129 : 0 : link->result = result;
1130 : : /* Note: The link is being added to the cache dict without the
1131 : : prev and next fields set to valid values. We have to wait
1132 : : for successful insertion in the cache dict before adding the
1133 : : link to the linked list. Otherwise, the potentially reentrant
1134 : : __eq__ call could cause the then orphan link to be visited. */
1135 [ # # ]: 0 : if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
1136 : : hash) < 0) {
1137 : : /* Somehow the cache dict update failed. We no longer can
1138 : : restore the old link. Let the error propagate upward and
1139 : : leave the cache short one link. */
1140 : 0 : Py_DECREF(popresult);
1141 : 0 : Py_DECREF(link);
1142 : 0 : Py_DECREF(oldkey);
1143 : 0 : Py_DECREF(oldresult);
1144 : 0 : return NULL;
1145 : : }
1146 : 0 : lru_cache_append_link(self, link);
1147 : 0 : Py_INCREF(result); /* for return */
1148 : 0 : Py_DECREF(popresult);
1149 : 0 : Py_DECREF(oldkey);
1150 : 0 : Py_DECREF(oldresult);
1151 : 0 : return result;
1152 : : }
1153 : :
1154 : : static PyObject *
1155 : 38 : lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
1156 : : {
1157 : : PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
1158 : : int typed;
1159 : : lru_cache_object *obj;
1160 : : Py_ssize_t maxsize;
1161 : : PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
1162 : : _functools_state *state;
1163 : : static char *keywords[] = {"user_function", "maxsize", "typed",
1164 : : "cache_info_type", NULL};
1165 : :
1166 [ - + ]: 38 : if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
1167 : : &func, &maxsize_O, &typed,
1168 : : &cache_info_type)) {
1169 : 0 : return NULL;
1170 : : }
1171 : :
1172 [ - + ]: 38 : if (!PyCallable_Check(func)) {
1173 : 0 : PyErr_SetString(PyExc_TypeError,
1174 : : "the first argument must be callable");
1175 : 0 : return NULL;
1176 : : }
1177 : :
1178 : 38 : state = get_functools_state_by_type(type);
1179 [ - + ]: 38 : if (state == NULL) {
1180 : 0 : return NULL;
1181 : : }
1182 : :
1183 : : /* select the caching function, and make/inc maxsize_O */
1184 [ - + ]: 38 : if (maxsize_O == Py_None) {
1185 : 0 : wrapper = infinite_lru_cache_wrapper;
1186 : : /* use this only to initialize lru_cache_object attribute maxsize */
1187 : 0 : maxsize = -1;
1188 [ + - ]: 38 : } else if (PyIndex_Check(maxsize_O)) {
1189 : 38 : maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1190 [ - + - - ]: 38 : if (maxsize == -1 && PyErr_Occurred())
1191 : 0 : return NULL;
1192 [ - + ]: 38 : if (maxsize < 0) {
1193 : 0 : maxsize = 0;
1194 : : }
1195 [ - + ]: 38 : if (maxsize == 0)
1196 : 0 : wrapper = uncached_lru_cache_wrapper;
1197 : : else
1198 : 38 : wrapper = bounded_lru_cache_wrapper;
1199 : : } else {
1200 : 0 : PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1201 : 0 : return NULL;
1202 : : }
1203 : :
1204 [ - + ]: 38 : if (!(cachedict = PyDict_New()))
1205 : 0 : return NULL;
1206 : :
1207 : 38 : obj = (lru_cache_object *)type->tp_alloc(type, 0);
1208 [ - + ]: 38 : if (obj == NULL) {
1209 : 0 : Py_DECREF(cachedict);
1210 : 0 : return NULL;
1211 : : }
1212 : :
1213 : 38 : obj->root.prev = &obj->root;
1214 : 38 : obj->root.next = &obj->root;
1215 : 38 : obj->wrapper = wrapper;
1216 : 38 : obj->typed = typed;
1217 : 38 : obj->cache = cachedict;
1218 : 38 : obj->func = Py_NewRef(func);
1219 : 38 : obj->misses = obj->hits = 0;
1220 : 38 : obj->maxsize = maxsize;
1221 : 38 : obj->kwd_mark = Py_NewRef(state->kwd_mark);
1222 : 38 : obj->lru_list_elem_type = (PyTypeObject*)Py_NewRef(state->lru_list_elem_type);
1223 : 38 : obj->cache_info_type = Py_NewRef(cache_info_type);
1224 : 38 : obj->dict = NULL;
1225 : 38 : obj->weakreflist = NULL;
1226 : 38 : return (PyObject *)obj;
1227 : : }
1228 : :
1229 : : static lru_list_elem *
1230 : 39 : lru_cache_unlink_list(lru_cache_object *self)
1231 : : {
1232 : 39 : lru_list_elem *root = &self->root;
1233 : 39 : lru_list_elem *link = root->next;
1234 [ + + ]: 39 : if (link == root)
1235 : 25 : return NULL;
1236 : 14 : root->prev->next = NULL;
1237 : 14 : root->next = root->prev = root;
1238 : 14 : return link;
1239 : : }
1240 : :
1241 : : static void
1242 : 39 : lru_cache_clear_list(lru_list_elem *link)
1243 : : {
1244 [ + + ]: 100 : while (link != NULL) {
1245 : 61 : lru_list_elem *next = link->next;
1246 : 61 : Py_SETREF(link, next);
1247 : : }
1248 : 39 : }
1249 : :
1250 : : static int
1251 : 38 : lru_cache_tp_clear(lru_cache_object *self)
1252 : : {
1253 : 38 : lru_list_elem *list = lru_cache_unlink_list(self);
1254 [ + - ]: 38 : Py_CLEAR(self->cache);
1255 [ + - ]: 38 : Py_CLEAR(self->func);
1256 [ + - ]: 38 : Py_CLEAR(self->kwd_mark);
1257 [ + - ]: 38 : Py_CLEAR(self->lru_list_elem_type);
1258 [ + - ]: 38 : Py_CLEAR(self->cache_info_type);
1259 [ + - ]: 38 : Py_CLEAR(self->dict);
1260 : 38 : lru_cache_clear_list(list);
1261 : 38 : return 0;
1262 : : }
1263 : :
1264 : : static void
1265 : 38 : lru_cache_dealloc(lru_cache_object *obj)
1266 : : {
1267 : 38 : PyTypeObject *tp = Py_TYPE(obj);
1268 : : /* bpo-31095: UnTrack is needed before calling any callbacks */
1269 : 38 : PyObject_GC_UnTrack(obj);
1270 [ - + ]: 38 : if (obj->weakreflist != NULL) {
1271 : 0 : PyObject_ClearWeakRefs((PyObject*)obj);
1272 : : }
1273 : :
1274 : 38 : (void)lru_cache_tp_clear(obj);
1275 : 38 : tp->tp_free(obj);
1276 : 38 : Py_DECREF(tp);
1277 : 38 : }
1278 : :
1279 : : static PyObject *
1280 : 81 : lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1281 : : {
1282 : 81 : return self->wrapper(self, args, kwds);
1283 : : }
1284 : :
1285 : : static PyObject *
1286 : 0 : lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1287 : : {
1288 [ # # # # ]: 0 : if (obj == Py_None || obj == NULL) {
1289 : 0 : return Py_NewRef(self);
1290 : : }
1291 : 0 : return PyMethod_New(self, obj);
1292 : : }
1293 : :
1294 : : /*[clinic input]
1295 : : _functools._lru_cache_wrapper.cache_info
1296 : :
1297 : : Report cache statistics
1298 : : [clinic start generated code]*/
1299 : :
1300 : : static PyObject *
1301 : 0 : _functools__lru_cache_wrapper_cache_info_impl(PyObject *self)
1302 : : /*[clinic end generated code: output=cc796a0b06dbd717 input=f05e5b6ebfe38645]*/
1303 : : {
1304 : 0 : lru_cache_object *_self = (lru_cache_object *) self;
1305 [ # # ]: 0 : if (_self->maxsize == -1) {
1306 : 0 : return PyObject_CallFunction(_self->cache_info_type, "nnOn",
1307 : : _self->hits, _self->misses, Py_None,
1308 : : PyDict_GET_SIZE(_self->cache));
1309 : : }
1310 : 0 : return PyObject_CallFunction(_self->cache_info_type, "nnnn",
1311 : : _self->hits, _self->misses, _self->maxsize,
1312 : : PyDict_GET_SIZE(_self->cache));
1313 : : }
1314 : :
1315 : : /*[clinic input]
1316 : : _functools._lru_cache_wrapper.cache_clear
1317 : :
1318 : : Clear the cache and cache statistics
1319 : : [clinic start generated code]*/
1320 : :
1321 : : static PyObject *
1322 : 1 : _functools__lru_cache_wrapper_cache_clear_impl(PyObject *self)
1323 : : /*[clinic end generated code: output=58423b35efc3e381 input=6ca59dba09b12584]*/
1324 : : {
1325 : 1 : lru_cache_object *_self = (lru_cache_object *) self;
1326 : 1 : lru_list_elem *list = lru_cache_unlink_list(_self);
1327 : 1 : _self->hits = _self->misses = 0;
1328 : 1 : PyDict_Clear(_self->cache);
1329 : 1 : lru_cache_clear_list(list);
1330 : 1 : Py_RETURN_NONE;
1331 : : }
1332 : :
1333 : : static PyObject *
1334 : 0 : lru_cache_reduce(PyObject *self, PyObject *unused)
1335 : : {
1336 : 0 : return PyObject_GetAttrString(self, "__qualname__");
1337 : : }
1338 : :
1339 : : static PyObject *
1340 : 0 : lru_cache_copy(PyObject *self, PyObject *unused)
1341 : : {
1342 : 0 : return Py_NewRef(self);
1343 : : }
1344 : :
1345 : : static PyObject *
1346 : 0 : lru_cache_deepcopy(PyObject *self, PyObject *unused)
1347 : : {
1348 : 0 : return Py_NewRef(self);
1349 : : }
1350 : :
1351 : : static int
1352 : 518 : lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1353 : : {
1354 [ + - - + ]: 518 : Py_VISIT(Py_TYPE(self));
1355 : 518 : lru_list_elem *link = self->root.next;
1356 [ + + ]: 1078 : while (link != &self->root) {
1357 : 560 : lru_list_elem *next = link->next;
1358 [ + - - + ]: 560 : Py_VISIT(link->key);
1359 [ + - - + ]: 560 : Py_VISIT(link->result);
1360 [ + - - + ]: 560 : Py_VISIT(Py_TYPE(link));
1361 : 560 : link = next;
1362 : : }
1363 [ + - - + ]: 518 : Py_VISIT(self->cache);
1364 [ + - - + ]: 518 : Py_VISIT(self->func);
1365 [ + - - + ]: 518 : Py_VISIT(self->kwd_mark);
1366 [ + - - + ]: 518 : Py_VISIT(self->lru_list_elem_type);
1367 [ + - - + ]: 518 : Py_VISIT(self->cache_info_type);
1368 [ + - - + ]: 518 : Py_VISIT(self->dict);
1369 : 518 : return 0;
1370 : : }
1371 : :
1372 : :
1373 : : PyDoc_STRVAR(lru_cache_doc,
1374 : : "Create a cached callable that wraps another function.\n\
1375 : : \n\
1376 : : user_function: the function being cached\n\
1377 : : \n\
1378 : : maxsize: 0 for no caching\n\
1379 : : None for unlimited cache size\n\
1380 : : n for a bounded cache\n\
1381 : : \n\
1382 : : typed: False cache f(3) and f(3.0) as identical calls\n\
1383 : : True cache f(3) and f(3.0) as distinct calls\n\
1384 : : \n\
1385 : : cache_info_type: namedtuple class with the fields:\n\
1386 : : hits misses currsize maxsize\n"
1387 : : );
1388 : :
1389 : : static PyMethodDef lru_cache_methods[] = {
1390 : : _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_INFO_METHODDEF
1391 : : _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_CLEAR_METHODDEF
1392 : : {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
1393 : : {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1394 : : {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
1395 : : {NULL}
1396 : : };
1397 : :
1398 : : static PyGetSetDef lru_cache_getsetlist[] = {
1399 : : {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1400 : : {NULL}
1401 : : };
1402 : :
1403 : : static PyMemberDef lru_cache_memberlist[] = {
1404 : : {"__dictoffset__", T_PYSSIZET,
1405 : : offsetof(lru_cache_object, dict), READONLY},
1406 : : {"__weaklistoffset__", T_PYSSIZET,
1407 : : offsetof(lru_cache_object, weakreflist), READONLY},
1408 : : {NULL} /* Sentinel */
1409 : : };
1410 : :
1411 : : static PyType_Slot lru_cache_type_slots[] = {
1412 : : {Py_tp_dealloc, lru_cache_dealloc},
1413 : : {Py_tp_call, lru_cache_call},
1414 : : {Py_tp_doc, (void *)lru_cache_doc},
1415 : : {Py_tp_traverse, lru_cache_tp_traverse},
1416 : : {Py_tp_clear, lru_cache_tp_clear},
1417 : : {Py_tp_methods, lru_cache_methods},
1418 : : {Py_tp_members, lru_cache_memberlist},
1419 : : {Py_tp_getset, lru_cache_getsetlist},
1420 : : {Py_tp_descr_get, lru_cache_descr_get},
1421 : : {Py_tp_new, lru_cache_new},
1422 : : {0, 0}
1423 : : };
1424 : :
1425 : : static PyType_Spec lru_cache_type_spec = {
1426 : : .name = "functools._lru_cache_wrapper",
1427 : : .basicsize = sizeof(lru_cache_object),
1428 : : .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1429 : : Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_IMMUTABLETYPE,
1430 : : .slots = lru_cache_type_slots
1431 : : };
1432 : :
1433 : :
1434 : : /* module level code ********************************************************/
1435 : :
1436 : : PyDoc_STRVAR(_functools_doc,
1437 : : "Tools that operate on functions.");
1438 : :
1439 : : static PyMethodDef _functools_methods[] = {
1440 : : {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
1441 : : _FUNCTOOLS_CMP_TO_KEY_METHODDEF
1442 : : {NULL, NULL} /* sentinel */
1443 : : };
1444 : :
1445 : : static int
1446 : 6 : _functools_exec(PyObject *module)
1447 : : {
1448 : 6 : _functools_state *state = get_functools_state(module);
1449 : 6 : state->kwd_mark = _PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type);
1450 [ - + ]: 6 : if (state->kwd_mark == NULL) {
1451 : 0 : return -1;
1452 : : }
1453 : :
1454 : 6 : state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1455 : : &partial_type_spec, NULL);
1456 [ - + ]: 6 : if (state->partial_type == NULL) {
1457 : 0 : return -1;
1458 : : }
1459 [ - + ]: 6 : if (PyModule_AddType(module, state->partial_type) < 0) {
1460 : 0 : return -1;
1461 : : }
1462 : :
1463 : 6 : PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
1464 : : &lru_cache_type_spec, NULL);
1465 [ - + ]: 6 : if (lru_cache_type == NULL) {
1466 : 0 : return -1;
1467 : : }
1468 [ - + ]: 6 : if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
1469 : 0 : Py_DECREF(lru_cache_type);
1470 : 0 : return -1;
1471 : : }
1472 : 6 : Py_DECREF(lru_cache_type);
1473 : :
1474 : 6 : state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1475 : : &keyobject_type_spec, NULL);
1476 [ - + ]: 6 : if (state->keyobject_type == NULL) {
1477 : 0 : return -1;
1478 : : }
1479 : : // keyobject_type is used only internally.
1480 : : // So we don't expose it in module namespace.
1481 : :
1482 : 6 : state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
1483 : : module, &lru_list_elem_type_spec, NULL);
1484 [ - + ]: 6 : if (state->lru_list_elem_type == NULL) {
1485 : 0 : return -1;
1486 : : }
1487 : : // lru_list_elem is used only in _lru_cache_wrapper.
1488 : : // So we don't expose it in module namespace.
1489 : :
1490 : 6 : return 0;
1491 : : }
1492 : :
1493 : : static int
1494 : 84 : _functools_traverse(PyObject *module, visitproc visit, void *arg)
1495 : : {
1496 : 84 : _functools_state *state = get_functools_state(module);
1497 [ + - - + ]: 84 : Py_VISIT(state->kwd_mark);
1498 [ + - - + ]: 84 : Py_VISIT(state->partial_type);
1499 [ + - - + ]: 84 : Py_VISIT(state->keyobject_type);
1500 [ + - - + ]: 84 : Py_VISIT(state->lru_list_elem_type);
1501 : 84 : return 0;
1502 : : }
1503 : :
1504 : : static int
1505 : 12 : _functools_clear(PyObject *module)
1506 : : {
1507 : 12 : _functools_state *state = get_functools_state(module);
1508 [ + + ]: 12 : Py_CLEAR(state->kwd_mark);
1509 [ + + ]: 12 : Py_CLEAR(state->partial_type);
1510 [ + + ]: 12 : Py_CLEAR(state->keyobject_type);
1511 [ + + ]: 12 : Py_CLEAR(state->lru_list_elem_type);
1512 : 12 : return 0;
1513 : : }
1514 : :
1515 : : static void
1516 : 6 : _functools_free(void *module)
1517 : : {
1518 : 6 : _functools_clear((PyObject *)module);
1519 : 6 : }
1520 : :
1521 : : static struct PyModuleDef_Slot _functools_slots[] = {
1522 : : {Py_mod_exec, _functools_exec},
1523 : : {0, NULL}
1524 : : };
1525 : :
1526 : : static struct PyModuleDef _functools_module = {
1527 : : PyModuleDef_HEAD_INIT,
1528 : : .m_name = "_functools",
1529 : : .m_doc = _functools_doc,
1530 : : .m_size = sizeof(_functools_state),
1531 : : .m_methods = _functools_methods,
1532 : : .m_slots = _functools_slots,
1533 : : .m_traverse = _functools_traverse,
1534 : : .m_clear = _functools_clear,
1535 : : .m_free = _functools_free,
1536 : : };
1537 : :
1538 : : PyMODINIT_FUNC
1539 : 6 : PyInit__functools(void)
1540 : : {
1541 : 6 : return PyModuleDef_Init(&_functools_module);
1542 : : }
|