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