Coverage Report

Created: 2026-10-17 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Modules/_functoolsmodule.c
Line
Count
Source
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_pyatomic_ft_wrappers.h"
8
#include "pycore_pystate.h"       // _PyThreadState_GET()
9
#include "pycore_tuple.h"         // _PyTuple_ITEMS()
10
#include "pycore_weakref.h"       // FT_CLEAR_WEAKREFS()
11
12
13
#include "clinic/_functoolsmodule.c.h"
14
/*[clinic input]
15
module _functools
16
class _functools._lru_cache_wrapper "PyObject *" "&lru_cache_type_spec"
17
[clinic start generated code]*/
18
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bece4053896b09c0]*/
19
20
/* _functools module written and maintained
21
   by Hye-Shik Chang <perky@FreeBSD.org>
22
   with adaptations by Raymond Hettinger <python@rcn.com>
23
   Copyright (c) 2004 Python Software Foundation.
24
   All rights reserved.
25
*/
26
27
typedef struct _functools_state {
28
    /* this object is used delimit args and keywords in the cache keys */
29
    PyObject *kwd_mark;
30
    PyTypeObject *placeholder_type;
31
    PyObject *placeholder;  // strong reference (singleton)
32
    PyTypeObject *partial_type;
33
    PyTypeObject *keyobject_type;
34
    PyTypeObject *lru_list_elem_type;
35
} _functools_state;
36
37
static inline _functools_state *
38
get_functools_state(PyObject *module)
39
182k
{
40
182k
    void *state = _PyModule_GetState(module);
41
182k
    assert(state != NULL);
42
182k
    return (_functools_state *)state;
43
182k
}
44
45
/* partial object **********************************************************/
46
47
48
// The 'Placeholder' singleton indicates which formal positional
49
// parameters are to be bound first when using a 'partial' object.
50
51
typedef struct {
52
    PyObject_HEAD
53
} placeholderobject;
54
55
static inline _functools_state *
56
get_functools_state_by_type(PyTypeObject *type);
57
58
PyDoc_STRVAR(placeholder_doc,
59
"The type of the Placeholder singleton.\n\n"
60
"Used as a placeholder for partial arguments.");
61
62
static PyObject *
63
placeholder_repr(PyObject *op)
64
0
{
65
0
    return PyUnicode_FromString("Placeholder");
66
0
}
67
68
static PyObject *
69
placeholder_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
70
0
{
71
0
    return PyUnicode_FromString("Placeholder");
72
0
}
73
74
static PyMethodDef placeholder_methods[] = {
75
    {"__reduce__", placeholder_reduce, METH_NOARGS, NULL},
76
    {NULL, NULL}
77
};
78
79
static void
80
placeholder_dealloc(PyObject* self)
81
0
{
82
0
    PyObject_GC_UnTrack(self);
83
0
    PyTypeObject *tp = Py_TYPE(self);
84
0
    tp->tp_free((PyObject*)self);
85
0
    Py_DECREF(tp);
86
0
}
87
88
static PyObject *
89
placeholder_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
90
28
{
91
28
    if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) {
92
0
        PyErr_SetString(PyExc_TypeError, "PlaceholderType takes no arguments");
93
0
        return NULL;
94
0
    }
95
28
    _functools_state *state = get_functools_state_by_type(type);
96
28
    if (state->placeholder != NULL) {
97
0
        return Py_NewRef(state->placeholder);
98
0
    }
99
100
28
    PyObject *placeholder = PyType_GenericNew(type, NULL, NULL);
101
28
    if (placeholder == NULL) {
102
0
        return NULL;
103
0
    }
104
105
28
    if (state->placeholder == NULL) {
106
28
        state->placeholder = Py_NewRef(placeholder);
107
28
    }
108
28
    return placeholder;
109
28
}
110
111
static PyType_Slot placeholder_type_slots[] = {
112
    {Py_tp_dealloc, placeholder_dealloc},
113
    {Py_tp_repr, placeholder_repr},
114
    {Py_tp_doc, (void *)placeholder_doc},
115
    {Py_tp_methods, placeholder_methods},
116
    {Py_tp_new, placeholder_new},
117
    {Py_tp_traverse, _PyObject_VisitType},
118
    {0, 0}
119
};
120
121
static PyType_Spec placeholder_type_spec = {
122
    .name = "functools._PlaceholderType",
123
    .basicsize = sizeof(placeholderobject),
124
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC,
125
    .slots = placeholder_type_slots
126
};
127
128
129
typedef struct {
130
    PyObject_HEAD
131
    PyObject *fn;
132
    PyObject *args;
133
    PyObject *kw;
134
    PyObject *dict;        /* __dict__ */
135
    PyObject *weakreflist; /* List of weak references */
136
    PyObject *placeholder; /* Placeholder for positional arguments */
137
    Py_ssize_t phcount;    /* Number of placeholders */
138
    vectorcallfunc vectorcall;
139
} partialobject;
140
141
// cast a PyObject pointer PTR to a partialobject pointer (no type checks)
142
676k
#define partialobject_CAST(op)  ((partialobject *)(op))
143
144
static void partial_setvectorcall(partialobject *pto);
145
static struct PyModuleDef _functools_module;
146
static PyObject *
147
partial_call(PyObject *pto, PyObject *args, PyObject *kwargs);
148
149
static inline _functools_state *
150
get_functools_state_by_type(PyTypeObject *type)
151
181k
{
152
181k
    PyObject *module = PyType_GetModuleByDef(type, &_functools_module);
153
181k
    if (module == NULL) {
154
0
        return NULL;
155
0
    }
156
181k
    return get_functools_state(module);
157
181k
}
158
159
// Not converted to argument clinic, because of `*args, **kwargs` arguments.
160
static PyObject *
161
partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
162
181k
{
163
181k
    PyObject *func, *pto_args, *new_args, *pto_kw, *phold;
164
181k
    partialobject *pto;
165
181k
    Py_ssize_t pto_phcount = 0;
166
181k
    Py_ssize_t new_nargs = PyTuple_GET_SIZE(args) - 1;
167
168
181k
    if (new_nargs < 0) {
169
0
        PyErr_SetString(PyExc_TypeError,
170
0
                        "type 'partial' takes at least one argument");
171
0
        return NULL;
172
0
    }
173
181k
    func = PyTuple_GET_ITEM(args, 0);
174
181k
    if (!PyCallable_Check(func)) {
175
0
        PyErr_SetString(PyExc_TypeError,
176
0
                        "the first argument must be callable");
177
0
        return NULL;
178
0
    }
179
180
181k
    _functools_state *state = get_functools_state_by_type(type);
181
181k
    if (state == NULL) {
182
0
        return NULL;
183
0
    }
184
181k
    phold = state->placeholder;
185
186
    /* Placeholder restrictions */
187
181k
    if (new_nargs && PyTuple_GET_ITEM(args, new_nargs) == phold) {
188
0
        PyErr_SetString(PyExc_TypeError,
189
0
                        "trailing Placeholders are not allowed");
190
0
        return NULL;
191
0
    }
192
193
    /* keyword Placeholder prohibition */
194
181k
    if (kw != NULL) {
195
180k
        PyObject *key, *val;
196
180k
        Py_ssize_t pos = 0;
197
438k
        while (PyDict_Next(kw, &pos, &key, &val)) {
198
257k
            if (val == phold) {
199
0
                PyErr_SetString(PyExc_TypeError,
200
0
                                "Placeholder cannot be passed as a keyword argument");
201
0
                return NULL;
202
0
            }
203
257k
        }
204
180k
    }
205
206
    /* check wrapped function / object */
207
181k
    pto_args = pto_kw = NULL;
208
181k
    int res = PyObject_TypeCheck(func, state->partial_type);
209
181k
    if (res == -1) {
210
0
        return NULL;
211
0
    }
212
181k
    if (res == 1) {
213
        // We can use its underlying function directly and merge the arguments.
214
0
        partialobject *part = (partialobject *)func;
215
0
        if (part->dict == NULL) {
216
0
            pto_args = part->args;
217
0
            pto_kw = part->kw;
218
0
            func = part->fn;
219
0
            pto_phcount = part->phcount;
220
0
            assert(PyTuple_Check(pto_args));
221
0
            assert(PyDict_Check(pto_kw));
222
0
        }
223
0
    }
224
225
    /* create partialobject structure */
226
181k
    pto = (partialobject *)type->tp_alloc(type, 0);
227
181k
    if (pto == NULL)
228
0
        return NULL;
229
230
181k
    pto->fn = Py_NewRef(func);
231
181k
    pto->placeholder = phold;
232
233
181k
    new_args = PyTuple_GetSlice(args, 1, new_nargs + 1);
234
181k
    if (new_args == NULL) {
235
0
        Py_DECREF(pto);
236
0
        return NULL;
237
0
    }
238
239
    /* Count placeholders */
240
181k
    Py_ssize_t phcount = 0;
241
181k
    for (Py_ssize_t i = 0; i < new_nargs - 1; i++) {
242
0
        if (PyTuple_GET_ITEM(new_args, i) == phold) {
243
0
            phcount++;
244
0
        }
245
0
    }
246
    /* merge args with args of `func` which is `partial` */
247
181k
    if (pto_phcount > 0 && new_nargs > 0) {
248
0
        Py_ssize_t npargs = PyTuple_GET_SIZE(pto_args);
249
0
        Py_ssize_t tot_nargs = npargs;
250
0
        if (new_nargs > pto_phcount) {
251
0
            tot_nargs += new_nargs - pto_phcount;
252
0
        }
253
0
        PyObject *item;
254
0
        PyObject *tot_args = PyTuple_New(tot_nargs);
255
0
        if (tot_args == NULL) {
256
0
            Py_DECREF(new_args);
257
0
            Py_DECREF(pto);
258
0
            return NULL;
259
0
        }
260
0
        for (Py_ssize_t i = 0, j = 0; i < tot_nargs; i++) {
261
0
            if (i < npargs) {
262
0
                item = PyTuple_GET_ITEM(pto_args, i);
263
0
                if (j < new_nargs && item == phold) {
264
0
                    item = PyTuple_GET_ITEM(new_args, j);
265
0
                    j++;
266
0
                    pto_phcount--;
267
0
                }
268
0
            }
269
0
            else {
270
0
                item = PyTuple_GET_ITEM(new_args, j);
271
0
                j++;
272
0
            }
273
0
            Py_INCREF(item);
274
0
            PyTuple_SET_ITEM(tot_args, i, item);
275
0
        }
276
0
        pto->args = tot_args;
277
0
        pto->phcount = pto_phcount + phcount;
278
0
        Py_DECREF(new_args);
279
0
    }
280
181k
    else if (pto_args == NULL) {
281
181k
        pto->args = new_args;
282
181k
        pto->phcount = phcount;
283
181k
    }
284
0
    else {
285
0
        pto->args = PySequence_Concat(pto_args, new_args);
286
0
        pto->phcount = pto_phcount + phcount;
287
0
        Py_DECREF(new_args);
288
0
        if (pto->args == NULL) {
289
0
            Py_DECREF(pto);
290
0
            return NULL;
291
0
        }
292
0
        assert(PyTuple_Check(pto->args));
293
0
    }
294
295
181k
    if (pto_kw == NULL || PyDict_GET_SIZE(pto_kw) == 0) {
296
181k
        if (kw == NULL) {
297
24
            pto->kw = PyDict_New();
298
24
        }
299
180k
        else if (_PyObject_IsUniquelyReferenced(kw)) {
300
180k
            pto->kw = Py_NewRef(kw);
301
180k
        }
302
0
        else {
303
0
            pto->kw = PyDict_Copy(kw);
304
0
        }
305
181k
    }
306
0
    else {
307
0
        pto->kw = PyDict_Copy(pto_kw);
308
0
        if (kw != NULL && pto->kw != NULL) {
309
0
            if (PyDict_Merge(pto->kw, kw, 1) != 0) {
310
0
                Py_DECREF(pto);
311
0
                return NULL;
312
0
            }
313
0
        }
314
0
    }
315
181k
    if (pto->kw == NULL) {
316
0
        Py_DECREF(pto);
317
0
        return NULL;
318
0
    }
319
320
181k
    partial_setvectorcall(pto);
321
181k
    return (PyObject *)pto;
322
181k
}
323
324
static int
325
partial_clear(PyObject *self)
326
180k
{
327
180k
    partialobject *pto = partialobject_CAST(self);
328
180k
    Py_CLEAR(pto->fn);
329
180k
    Py_CLEAR(pto->args);
330
180k
    Py_CLEAR(pto->kw);
331
180k
    Py_CLEAR(pto->dict);
332
180k
    return 0;
333
180k
}
334
335
static int
336
partial_traverse(PyObject *self, visitproc visit, void *arg)
337
458k
{
338
458k
    partialobject *pto = partialobject_CAST(self);
339
458k
    Py_VISIT(Py_TYPE(pto));
340
458k
    Py_VISIT(pto->fn);
341
458k
    Py_VISIT(pto->args);
342
458k
    Py_VISIT(pto->kw);
343
458k
    Py_VISIT(pto->dict);
344
458k
    return 0;
345
458k
}
346
347
static void
348
partial_dealloc(PyObject *self)
349
180k
{
350
180k
    PyTypeObject *tp = Py_TYPE(self);
351
    /* bpo-31095: UnTrack is needed before calling any callbacks */
352
180k
    PyObject_GC_UnTrack(self);
353
180k
    FT_CLEAR_WEAKREFS(self, partialobject_CAST(self)->weakreflist);
354
180k
    (void)partial_clear(self);
355
180k
    tp->tp_free(self);
356
180k
    Py_DECREF(tp);
357
180k
}
358
359
static PyObject *
360
partial_descr_get(PyObject *self, PyObject *obj, PyObject *type)
361
0
{
362
0
    if (obj == Py_None || obj == NULL) {
363
0
        return Py_NewRef(self);
364
0
    }
365
0
    return PyMethod_New(self, obj);
366
0
}
367
368
static PyObject *
369
partial_vectorcall(PyObject *self, PyObject *const *args,
370
                   size_t nargsf, PyObject *kwnames)
371
37.9k
{
372
37.9k
    partialobject *pto = partialobject_CAST(self);;
373
37.9k
    PyThreadState *tstate = _PyThreadState_GET();
374
37.9k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
375
376
    /* Placeholder check */
377
37.9k
    Py_ssize_t pto_phcount = pto->phcount;
378
37.9k
    if (nargs < pto_phcount) {
379
0
        PyErr_Format(PyExc_TypeError,
380
0
                     "missing positional arguments in 'partial' call; "
381
0
                     "expected at least %zd, got %zd", pto_phcount, nargs);
382
0
        return NULL;
383
0
    }
384
385
37.9k
    PyObject *result = NULL;
386
37.9k
    PyObject *partial_function = Py_NewRef(pto->fn);
387
37.9k
    PyObject *partial_args = Py_NewRef(pto->args);
388
37.9k
    PyObject *partial_keywords = Py_NewRef(pto->kw);
389
390
37.9k
    PyObject **pto_args = _PyTuple_ITEMS(partial_args);
391
37.9k
    Py_ssize_t pto_nargs = PyTuple_GET_SIZE(partial_args);
392
37.9k
    Py_ssize_t pto_nkwds = PyDict_GET_SIZE(partial_keywords);
393
37.9k
    Py_ssize_t nkwds = kwnames == NULL ? 0 : PyTuple_GET_SIZE(kwnames);
394
37.9k
    Py_ssize_t nargskw = nargs + nkwds;
395
396
    /* Special cases */
397
37.9k
    if (!pto_nkwds) {
398
        /* Fast path if we're called without arguments */
399
32.3k
        if (nargskw == 0) {
400
0
            result = _PyObject_VectorcallTstate(tstate, partial_function, pto_args,
401
0
                                                pto_nargs, NULL);
402
0
            goto done;
403
0
        }
404
405
        /* Use PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
406
         * positional argument. */
407
32.3k
        if (pto_nargs == 1 && (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET)) {
408
32.3k
            PyObject **newargs = (PyObject **)args - 1;
409
32.3k
            PyObject *tmp = newargs[0];
410
32.3k
            newargs[0] = pto_args[0];
411
32.3k
            result = _PyObject_VectorcallTstate(tstate, partial_function, newargs,
412
32.3k
                                                nargs + 1, kwnames);
413
32.3k
            newargs[0] = tmp;
414
32.3k
            goto done;
415
32.3k
        }
416
32.3k
    }
417
418
    /* Total sizes */
419
5.65k
    Py_ssize_t tot_nargs = pto_nargs + nargs - pto_phcount;
420
5.65k
    Py_ssize_t tot_nkwds = pto_nkwds + nkwds;
421
5.65k
    Py_ssize_t tot_nargskw = tot_nargs + tot_nkwds;
422
423
5.65k
    PyObject *pto_kw_merged = NULL;  // pto_kw with duplicates merged (if any)
424
5.65k
    PyObject *tot_kwnames;
425
426
    /* Allocate Stack
427
     * Note, _PY_FASTCALL_SMALL_STACK is optimal for positional only
428
     * This case might have keyword arguments
429
     *  furthermore, it might use extra stack space for temporary key storage
430
     *  thus, double small_stack size is used, which is 10 * 8 = 80 bytes */
431
5.65k
    PyObject *small_stack[_PY_FASTCALL_SMALL_STACK * 2];
432
5.65k
    PyObject **tmp_stack, **stack;
433
5.65k
    Py_ssize_t init_stack_size = tot_nargskw;
434
5.65k
    if (pto_nkwds) {
435
        // If pto_nkwds, allocate additional space for temporary new keys
436
5.65k
        init_stack_size += nkwds;
437
5.65k
    }
438
5.65k
    if (init_stack_size <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
439
5.65k
        stack = small_stack;
440
5.65k
    }
441
0
    else {
442
0
        stack = PyMem_Malloc(init_stack_size * sizeof(PyObject *));
443
0
        if (stack == NULL) {
444
0
            PyErr_NoMemory();
445
0
            goto done;
446
0
        }
447
0
    }
448
449
    /* Copy keywords to stack */
450
5.65k
    if (!pto_nkwds) {
451
0
        tot_kwnames = kwnames;
452
0
        if (nkwds) {
453
            /* if !pto_nkwds & nkwds, then simply append kw */
454
0
            memcpy(stack + tot_nargs, args + nargs, nkwds * sizeof(PyObject*));
455
0
        }
456
0
    }
457
5.65k
    else {
458
        /* stack is now         [<positionals>, <pto_kwds>, <kwds>, <kwds_keys>]
459
         * Will resize later to [<positionals>, <merged_kwds>] */
460
5.65k
        PyObject *key, *val;
461
462
        /* Merge kw to pto_kw or add to tail (if not duplicate) */
463
5.65k
        Py_ssize_t n_tail = 0;
464
5.65k
        for (Py_ssize_t i = 0; i < nkwds; ++i) {
465
0
            key = PyTuple_GET_ITEM(kwnames, i);
466
0
            val = args[nargs + i];
467
0
            int contains = PyDict_Contains(partial_keywords, key);
468
0
            if (contains < 0) {
469
0
                goto clean_stack;
470
0
            }
471
0
            else if (contains == 1) {
472
0
                if (pto_kw_merged == NULL) {
473
0
                    pto_kw_merged = PyDict_Copy(partial_keywords);
474
0
                    if (pto_kw_merged == NULL) {
475
0
                        goto clean_stack;
476
0
                    }
477
0
                }
478
0
                if (PyDict_SetItem(pto_kw_merged, key, val) < 0) {
479
0
                    Py_DECREF(pto_kw_merged);
480
0
                    goto clean_stack;
481
0
                }
482
0
            }
483
0
            else {
484
                /* Copy keyword tail to stack */
485
0
                stack[tot_nargs + pto_nkwds + n_tail] = val;
486
0
                stack[tot_nargskw + n_tail] = key;
487
0
                n_tail++;
488
0
            }
489
0
        }
490
5.65k
        Py_ssize_t n_merges = nkwds - n_tail;
491
492
        /* Create total kwnames */
493
5.65k
        tot_kwnames = PyTuple_New(tot_nkwds - n_merges);
494
5.65k
        if (tot_kwnames == NULL) {
495
0
            Py_XDECREF(pto_kw_merged);
496
0
            goto clean_stack;
497
0
        }
498
5.65k
        for (Py_ssize_t i = 0; i < n_tail; ++i) {
499
0
            key = Py_NewRef(stack[tot_nargskw + i]);
500
0
            PyTuple_SET_ITEM(tot_kwnames, pto_nkwds + i, key);
501
0
        }
502
503
        /* Copy pto_keywords with overlapping call keywords merged
504
         * Note, tail is already coppied. */
505
5.65k
        Py_ssize_t pos = 0, i = 0;
506
5.65k
        PyObject *keyword_dict = n_merges ? pto_kw_merged : partial_keywords;
507
5.65k
        Py_BEGIN_CRITICAL_SECTION(keyword_dict);
508
22.6k
        while (PyDict_Next(keyword_dict, &pos, &key, &val)) {
509
16.9k
            assert(i < pto_nkwds);
510
16.9k
            PyTuple_SET_ITEM(tot_kwnames, i, Py_NewRef(key));
511
16.9k
            stack[tot_nargs + i] = val;
512
16.9k
            i++;
513
16.9k
        }
514
5.65k
        Py_END_CRITICAL_SECTION();
515
5.65k
        assert(i == pto_nkwds);
516
5.65k
        Py_XDECREF(pto_kw_merged);
517
518
        /* Resize Stack if the removing overallocation saves some noticable memory
519
         * NOTE: This whole block can be removed without breaking anything */
520
5.65k
        Py_ssize_t noveralloc = n_merges + nkwds;
521
5.65k
        if (stack != small_stack && noveralloc > 6 && noveralloc > init_stack_size / 10) {
522
0
            tmp_stack = PyMem_Realloc(stack, (tot_nargskw - n_merges) * sizeof(PyObject *));
523
0
            if (tmp_stack == NULL) {
524
0
                Py_DECREF(tot_kwnames);
525
0
                PyErr_NoMemory();
526
0
                goto clean_stack;
527
0
            }
528
0
            stack = tmp_stack;
529
0
        }
530
5.65k
    }
531
532
    /* Copy Positionals to stack */
533
5.65k
    if (pto_phcount) {
534
0
        Py_ssize_t j = 0;       // New args index
535
0
        for (Py_ssize_t i = 0; i < pto_nargs; i++) {
536
0
            if (pto_args[i] == pto->placeholder) {
537
0
                stack[i] = args[j];
538
0
                j += 1;
539
0
            }
540
0
            else {
541
0
                stack[i] = pto_args[i];
542
0
            }
543
0
        }
544
0
        assert(j == pto_phcount);
545
        /* Add remaining args from new_args */
546
0
        if (nargs > pto_phcount) {
547
0
            memcpy(stack + pto_nargs, args + j, (nargs - j) * sizeof(PyObject*));
548
0
        }
549
0
    }
550
5.65k
    else {
551
5.65k
        memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
552
5.65k
        memcpy(stack + pto_nargs, args, nargs * sizeof(PyObject*));
553
5.65k
    }
554
555
5.65k
    result = _PyObject_VectorcallTstate(tstate, partial_function, stack,
556
5.65k
                                        tot_nargs, tot_kwnames);
557
5.65k
    if (pto_nkwds) {
558
5.65k
        Py_DECREF(tot_kwnames);
559
5.65k
    }
560
561
5.65k
 clean_stack:
562
5.65k
    if (stack != small_stack) {
563
0
        PyMem_Free(stack);
564
0
    }
565
566
37.9k
 done:
567
37.9k
    Py_DECREF(partial_function);
568
37.9k
    Py_DECREF(partial_args);
569
37.9k
    Py_DECREF(partial_keywords);
570
37.9k
    return result;
571
5.65k
}
572
573
/* Set pto->vectorcall depending on the parameters of the partial object */
574
static void
575
partial_setvectorcall(partialobject *pto)
576
181k
{
577
181k
    if (PyVectorcall_Function(pto->fn) == NULL) {
578
        /* Don't use vectorcall if the underlying function doesn't support it */
579
12
        pto->vectorcall = NULL;
580
12
    }
581
    /* We could have a special case if there are no arguments,
582
     * but that is unlikely (why use partial without arguments?),
583
     * so we don't optimize that */
584
181k
    else {
585
181k
        pto->vectorcall = partial_vectorcall;
586
181k
    }
587
181k
}
588
589
590
// Not converted to argument clinic, because of `*args, **kwargs` arguments.
591
static PyObject *
592
partial_call(PyObject *self, PyObject *args, PyObject *kwargs)
593
44
{
594
44
    partialobject *pto = partialobject_CAST(self);
595
44
    assert(PyCallable_Check(pto->fn));
596
44
    assert(PyTuple_Check(pto->args));
597
44
    assert(PyDict_Check(pto->kw));
598
599
44
    Py_ssize_t nargs = PyTuple_GET_SIZE(args);
600
44
    Py_ssize_t pto_phcount = pto->phcount;
601
44
    if (nargs < pto_phcount) {
602
0
        PyErr_Format(PyExc_TypeError,
603
0
                     "missing positional arguments in 'partial' call; "
604
0
                     "expected at least %zd, got %zd", pto_phcount, nargs);
605
0
        return NULL;
606
0
    }
607
608
    /* Merge keywords */
609
44
    PyObject *tot_kw;
610
44
    if (PyDict_GET_SIZE(pto->kw) == 0) {
611
        /* kwargs can be NULL */
612
44
        tot_kw = Py_XNewRef(kwargs);
613
44
    }
614
0
    else {
615
        /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
616
           copied, because a function using "**kwargs" can modify the
617
           dictionary. */
618
0
        tot_kw = PyDict_Copy(pto->kw);
619
0
        if (tot_kw == NULL) {
620
0
            return NULL;
621
0
        }
622
623
0
        if (kwargs != NULL) {
624
0
            if (PyDict_Merge(tot_kw, kwargs, 1) != 0) {
625
0
                Py_DECREF(tot_kw);
626
0
                return NULL;
627
0
            }
628
0
        }
629
0
    }
630
631
    /* Merge positional arguments */
632
44
    PyObject *tot_args;
633
44
    if (pto_phcount) {
634
0
        Py_ssize_t pto_nargs = PyTuple_GET_SIZE(pto->args);
635
0
        Py_ssize_t tot_nargs = pto_nargs + nargs - pto_phcount;
636
0
        assert(tot_nargs >= 0);
637
0
        tot_args = PyTuple_New(tot_nargs);
638
0
        if (tot_args == NULL) {
639
0
            Py_XDECREF(tot_kw);
640
0
            return NULL;
641
0
        }
642
0
        PyObject *pto_args = pto->args;
643
0
        PyObject *item;
644
0
        Py_ssize_t j = 0;   // New args index
645
0
        for (Py_ssize_t i = 0; i < pto_nargs; i++) {
646
0
            item = PyTuple_GET_ITEM(pto_args, i);
647
0
            if (item == pto->placeholder) {
648
0
                item = PyTuple_GET_ITEM(args, j);
649
0
                j += 1;
650
0
            }
651
0
            Py_INCREF(item);
652
0
            PyTuple_SET_ITEM(tot_args, i, item);
653
0
        }
654
0
        assert(j == pto_phcount);
655
0
        for (Py_ssize_t i = pto_nargs; i < tot_nargs; i++) {
656
0
            item = PyTuple_GET_ITEM(args, j);
657
0
            Py_INCREF(item);
658
0
            PyTuple_SET_ITEM(tot_args, i, item);
659
0
            j += 1;
660
0
        }
661
0
    }
662
44
    else {
663
        /* Note: tupleconcat() is optimized for empty tuples */
664
44
        tot_args = PySequence_Concat(pto->args, args);
665
44
        if (tot_args == NULL) {
666
0
            Py_XDECREF(tot_kw);
667
0
            return NULL;
668
0
        }
669
44
    }
670
671
44
    PyObject *res = PyObject_Call(pto->fn, tot_args, tot_kw);
672
44
    Py_DECREF(tot_args);
673
44
    Py_XDECREF(tot_kw);
674
44
    return res;
675
44
}
676
677
PyDoc_STRVAR(partial_doc,
678
"partial(func, /, *args, **keywords)\n--\n\n\
679
Create a new function with partial application of the given arguments\n\
680
and keywords.");
681
682
#define OFF(x) offsetof(partialobject, x)
683
static PyMemberDef partial_memberlist[] = {
684
    {"func",            _Py_T_OBJECT,       OFF(fn),        Py_READONLY,
685
     "function object to use in future partial calls"},
686
    {"args",            _Py_T_OBJECT,       OFF(args),      Py_READONLY,
687
     "tuple of arguments to future partial calls"},
688
    {"keywords",        _Py_T_OBJECT,       OFF(kw),        Py_READONLY,
689
     "dictionary of keyword arguments to future partial calls"},
690
    {"__weaklistoffset__", Py_T_PYSSIZET,
691
     offsetof(partialobject, weakreflist), Py_READONLY},
692
    {"__dictoffset__", Py_T_PYSSIZET,
693
     offsetof(partialobject, dict), Py_READONLY},
694
    {"__vectorcalloffset__", Py_T_PYSSIZET,
695
     offsetof(partialobject, vectorcall), Py_READONLY},
696
    {NULL}  /* Sentinel */
697
};
698
699
static PyGetSetDef partial_getsetlist[] = {
700
    {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
701
    {NULL} /* Sentinel */
702
};
703
704
static PyObject *
705
partial_repr(PyObject *self)
706
0
{
707
0
    partialobject *pto = partialobject_CAST(self);
708
0
    PyObject *result = NULL;
709
0
    PyObject *arglist = NULL;
710
0
    PyObject *mod = NULL;
711
0
    PyObject *name = NULL;
712
0
    Py_ssize_t i, n;
713
0
    PyObject *key, *value;
714
0
    int status;
715
716
0
    status = Py_ReprEnter(self);
717
0
    if (status != 0) {
718
0
        if (status < 0) {
719
0
            return NULL;
720
0
        }
721
0
        return PyUnicode_FromString("...");
722
0
    }
723
    /* Reference arguments in case they change */
724
0
    PyObject *fn = Py_NewRef(pto->fn);
725
0
    PyObject *args = Py_NewRef(pto->args);
726
0
    PyObject *kw = Py_NewRef(pto->kw);
727
0
    assert(PyTuple_Check(args));
728
0
    assert(PyDict_Check(kw));
729
730
0
    arglist = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
731
0
    if (arglist == NULL) {
732
0
        goto done;
733
0
    }
734
    /* Pack positional arguments */
735
0
    n = PyTuple_GET_SIZE(args);
736
0
    for (i = 0; i < n; i++) {
737
0
        Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
738
0
                                        PyTuple_GET_ITEM(args, i)));
739
0
        if (arglist == NULL) {
740
0
            goto done;
741
0
        }
742
0
    }
743
    /* Pack keyword arguments */
744
0
    int error = 0;
745
0
    Py_BEGIN_CRITICAL_SECTION(kw);
746
0
    for (i = 0; PyDict_Next(kw, &i, &key, &value);) {
747
        /* Prevent key.__str__ from deleting the value. */
748
0
        Py_INCREF(value);
749
0
        Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
750
0
                                                key, value));
751
0
        Py_DECREF(value);
752
0
        if (arglist == NULL) {
753
0
            error = 1;
754
0
            break;
755
0
        }
756
0
    }
757
0
    Py_END_CRITICAL_SECTION();
758
0
    if (error) {
759
0
        goto done;
760
0
    }
761
762
0
    mod = PyType_GetModuleName(Py_TYPE(pto));
763
0
    if (mod == NULL) {
764
0
        goto done;
765
0
    }
766
767
0
    name = PyType_GetQualName(Py_TYPE(pto));
768
0
    if (name == NULL) {
769
0
        goto done;
770
0
    }
771
772
0
    result = PyUnicode_FromFormat("%S.%S(%R%U)", mod, name, fn, arglist);
773
0
done:
774
0
    Py_XDECREF(name);
775
0
    Py_XDECREF(mod);
776
0
    Py_XDECREF(arglist);
777
0
    Py_DECREF(fn);
778
0
    Py_DECREF(args);
779
0
    Py_DECREF(kw);
780
0
    Py_ReprLeave(self);
781
0
    return result;
782
0
}
783
784
/* Pickle strategy:
785
   __reduce__ by itself doesn't support getting kwargs in the unpickle
786
   operation so we define a __setstate__ that replaces all the information
787
   about the partial.  If we only replaced part of it someone would use
788
   it as a hook to do strange things.
789
 */
790
791
static PyObject *
792
partial_reduce(PyObject *self, PyObject *Py_UNUSED(args))
793
0
{
794
0
    partialobject *pto = partialobject_CAST(self);
795
0
    return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
796
0
                         pto->args, pto->kw,
797
0
                         pto->dict ? pto->dict : Py_None);
798
0
}
799
800
static PyObject *
801
partial_setstate(PyObject *self, PyObject *state)
802
0
{
803
0
    partialobject *pto = partialobject_CAST(self);
804
0
    PyObject *fn, *fnargs, *kw, *dict;
805
806
0
    if (!PyTuple_Check(state)) {
807
0
        PyErr_SetString(PyExc_TypeError, "invalid partial state");
808
0
        return NULL;
809
0
    }
810
0
    if (!PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
811
0
        !PyCallable_Check(fn) ||
812
0
        !PyTuple_Check(fnargs) ||
813
0
        (kw != Py_None && !PyDict_Check(kw)) ||
814
0
        (dict != Py_None && !PyDict_Check(dict)))
815
0
    {
816
0
        PyErr_SetString(PyExc_TypeError, "invalid partial state");
817
0
        return NULL;
818
0
    }
819
820
0
    Py_ssize_t nargs = PyTuple_GET_SIZE(fnargs);
821
0
    if (nargs && PyTuple_GET_ITEM(fnargs, nargs - 1) == pto->placeholder) {
822
0
        PyErr_SetString(PyExc_TypeError,
823
0
                        "trailing Placeholders are not allowed");
824
0
        return NULL;
825
0
    }
826
    /* Count placeholders */
827
0
    Py_ssize_t phcount = 0;
828
0
    for (Py_ssize_t i = 0; i < nargs - 1; i++) {
829
0
        if (PyTuple_GET_ITEM(fnargs, i) == pto->placeholder) {
830
0
            phcount++;
831
0
        }
832
0
    }
833
834
0
    if(!PyTuple_CheckExact(fnargs))
835
0
        fnargs = PySequence_Tuple(fnargs);
836
0
    else
837
0
        Py_INCREF(fnargs);
838
0
    if (fnargs == NULL)
839
0
        return NULL;
840
841
0
    if (kw == Py_None)
842
0
        kw = PyDict_New();
843
0
    else if(!PyDict_CheckExact(kw))
844
0
        kw = PyDict_Copy(kw);
845
0
    else
846
0
        Py_INCREF(kw);
847
0
    if (kw == NULL) {
848
0
        Py_DECREF(fnargs);
849
0
        return NULL;
850
0
    }
851
852
0
    if (dict == Py_None)
853
0
        dict = NULL;
854
0
    else
855
0
        Py_INCREF(dict);
856
0
    Py_SETREF(pto->fn, Py_NewRef(fn));
857
0
    Py_SETREF(pto->args, fnargs);
858
0
    Py_SETREF(pto->kw, kw);
859
0
    pto->phcount = phcount;
860
0
    Py_XSETREF(pto->dict, dict);
861
0
    partial_setvectorcall(pto);
862
0
    Py_RETURN_NONE;
863
0
}
864
865
static PyMethodDef partial_methods[] = {
866
    {"__reduce__", partial_reduce, METH_NOARGS},
867
    {"__setstate__", partial_setstate, METH_O},
868
    {"__class_getitem__",    Py_GenericAlias,
869
    METH_O|METH_CLASS,
870
    PyDoc_STR("partial is generic over the wrapped function's return type")},
871
    {NULL,              NULL}           /* sentinel */
872
};
873
874
static PyType_Slot partial_type_slots[] = {
875
    {Py_tp_dealloc, partial_dealloc},
876
    {Py_tp_repr, partial_repr},
877
    {Py_tp_call, partial_call},
878
    {Py_tp_getattro, PyObject_GenericGetAttr},
879
    {Py_tp_setattro, PyObject_GenericSetAttr},
880
    {Py_tp_doc, (void *)partial_doc},
881
    {Py_tp_traverse, partial_traverse},
882
    {Py_tp_clear, partial_clear},
883
    {Py_tp_methods, partial_methods},
884
    {Py_tp_members, partial_memberlist},
885
    {Py_tp_getset, partial_getsetlist},
886
    {Py_tp_descr_get, partial_descr_get},
887
    {Py_tp_new, partial_new},
888
    {Py_tp_free, PyObject_GC_Del},
889
    {0, 0}
890
};
891
892
static PyType_Spec partial_type_spec = {
893
    .name = "functools.partial",
894
    .basicsize = sizeof(partialobject),
895
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
896
             Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL |
897
             Py_TPFLAGS_IMMUTABLETYPE,
898
    .slots = partial_type_slots
899
};
900
901
902
/* cmp_to_key ***************************************************************/
903
904
typedef struct {
905
    PyObject_HEAD
906
    PyObject *cmp;
907
    PyObject *object;
908
} keyobject;
909
910
0
#define keyobject_CAST(op)  ((keyobject *)(op))
911
912
static int
913
keyobject_clear(PyObject *op)
914
0
{
915
0
    keyobject *ko = keyobject_CAST(op);
916
0
    Py_CLEAR(ko->cmp);
917
0
    Py_CLEAR(ko->object);
918
0
    return 0;
919
0
}
920
921
static void
922
keyobject_dealloc(PyObject *ko)
923
0
{
924
0
    PyTypeObject *tp = Py_TYPE(ko);
925
0
    PyObject_GC_UnTrack(ko);
926
0
    (void)keyobject_clear(ko);
927
0
    tp->tp_free(ko);
928
0
    Py_DECREF(tp);
929
0
}
930
931
static int
932
keyobject_traverse(PyObject *op, visitproc visit, void *arg)
933
0
{
934
0
    keyobject *ko = keyobject_CAST(op);
935
0
    Py_VISIT(Py_TYPE(ko));
936
0
    Py_VISIT(ko->cmp);
937
0
    Py_VISIT(ko->object);
938
0
    return 0;
939
0
}
940
941
static PyMemberDef keyobject_members[] = {
942
    {"obj", _Py_T_OBJECT,
943
     offsetof(keyobject, object), 0,
944
     PyDoc_STR("Value wrapped by a key function.")},
945
    {NULL}
946
};
947
948
static PyObject *
949
keyobject_text_signature(PyObject *Py_UNUSED(self), void *Py_UNUSED(ignored))
950
0
{
951
0
    return PyUnicode_FromString("(obj)");
952
0
}
953
954
static PyGetSetDef keyobject_getset[] = {
955
    {"__text_signature__", keyobject_text_signature, NULL},
956
    {NULL}
957
};
958
959
static PyObject *
960
keyobject_call(PyObject *ko, PyObject *args, PyObject *kwds);
961
962
static PyObject *
963
keyobject_richcompare(PyObject *ko, PyObject *other, int op);
964
965
static PyType_Slot keyobject_type_slots[] = {
966
    {Py_tp_dealloc, keyobject_dealloc},
967
    {Py_tp_call, keyobject_call},
968
    {Py_tp_getattro, PyObject_GenericGetAttr},
969
    {Py_tp_traverse, keyobject_traverse},
970
    {Py_tp_clear, keyobject_clear},
971
    {Py_tp_richcompare, keyobject_richcompare},
972
    {Py_tp_members, keyobject_members},
973
    {Py_tp_getset, keyobject_getset},
974
    {0, 0}
975
};
976
977
static PyType_Spec keyobject_type_spec = {
978
    .name = "functools.KeyWrapper",
979
    .basicsize = sizeof(keyobject),
980
    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
981
              Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
982
    .slots = keyobject_type_slots
983
};
984
985
static PyObject *
986
keyobject_call(PyObject *self, PyObject *args, PyObject *kwds)
987
0
{
988
0
    PyObject *object;
989
0
    keyobject *result;
990
0
    static char *kwargs[] = {"obj", NULL};
991
0
    keyobject *ko = keyobject_CAST(self);
992
993
0
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
994
0
        return NULL;
995
996
0
    result = PyObject_GC_New(keyobject, Py_TYPE(ko));
997
0
    if (result == NULL) {
998
0
        return NULL;
999
0
    }
1000
0
    result->cmp = Py_NewRef(ko->cmp);
1001
0
    result->object = Py_NewRef(object);
1002
0
    PyObject_GC_Track(result);
1003
0
    return (PyObject *)result;
1004
0
}
1005
1006
static PyObject *
1007
keyobject_richcompare(PyObject *self, PyObject *other, int op)
1008
0
{
1009
0
    if (!Py_IS_TYPE(other, Py_TYPE(self))) {
1010
0
        PyErr_Format(PyExc_TypeError, "other argument must be K instance");
1011
0
        return NULL;
1012
0
    }
1013
1014
0
    keyobject *lhs = keyobject_CAST(self);
1015
0
    keyobject *rhs = keyobject_CAST(other);
1016
1017
0
    PyObject *compare = lhs->cmp;
1018
0
    assert(compare != NULL);
1019
0
    PyObject *x = lhs->object;
1020
0
    PyObject *y = rhs->object;
1021
0
    if (!x || !y){
1022
0
        PyErr_Format(PyExc_AttributeError, "object");
1023
0
        return NULL;
1024
0
    }
1025
1026
    /* Call the user's comparison function and translate the 3-way
1027
     * result into true or false (or error).
1028
     */
1029
0
    PyObject* args[2] = {x, y};
1030
0
    PyObject *res = PyObject_Vectorcall(compare, args, 2, NULL);
1031
0
    if (res == NULL) {
1032
0
        return NULL;
1033
0
    }
1034
1035
0
    PyObject *answer = PyObject_RichCompare(res, _PyLong_GetZero(), op);
1036
0
    Py_DECREF(res);
1037
0
    return answer;
1038
0
}
1039
1040
/*[clinic input]
1041
_functools.cmp_to_key
1042
1043
    mycmp: object
1044
        Function that compares two objects.
1045
1046
Convert a cmp= function into a key= function.
1047
[clinic start generated code]*/
1048
1049
static PyObject *
1050
_functools_cmp_to_key_impl(PyObject *module, PyObject *mycmp)
1051
/*[clinic end generated code: output=71eaad0f4fc81f33 input=d1b76f231c0dfeb3]*/
1052
0
{
1053
0
    keyobject *object;
1054
0
    _functools_state *state;
1055
1056
0
    state = get_functools_state(module);
1057
0
    object = PyObject_GC_New(keyobject, state->keyobject_type);
1058
0
    if (!object)
1059
0
        return NULL;
1060
0
    object->cmp = Py_NewRef(mycmp);
1061
0
    object->object = NULL;
1062
0
    PyObject_GC_Track(object);
1063
0
    return (PyObject *)object;
1064
0
}
1065
1066
/* reduce (used to be a builtin) ********************************************/
1067
1068
/*[clinic input]
1069
@permit_long_summary
1070
_functools.reduce
1071
1072
    function as func: object
1073
    iterable as seq: object
1074
    /
1075
    initial as result: object(c_default="NULL") = functools._initial_missing
1076
1077
Apply a function of two arguments cumulatively to the items of an iterable, from left to right.
1078
1079
This effectively reduces the iterable to a single value.  If initial is
1080
present, it is placed before the items of the iterable in the
1081
calculation, and serves as a default when the iterable is empty.
1082
1083
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
1084
calculates ((((1 + 2) + 3) + 4) + 5).
1085
[clinic start generated code]*/
1086
1087
static PyObject *
1088
_functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq,
1089
                       PyObject *result)
1090
/*[clinic end generated code: output=30d898fe1267c79d input=ff4d5c73100e72e8]*/
1091
0
{
1092
0
    PyObject *args, *it;
1093
1094
0
    if (result != NULL)
1095
0
        Py_INCREF(result);
1096
1097
0
    it = PyObject_GetIter(seq);
1098
0
    if (it == NULL) {
1099
0
        if (PyErr_ExceptionMatches(PyExc_TypeError))
1100
0
            PyErr_SetString(PyExc_TypeError,
1101
0
                            "reduce() arg 2 must support iteration");
1102
0
        Py_XDECREF(result);
1103
0
        return NULL;
1104
0
    }
1105
1106
0
    if ((args = PyTuple_New(2)) == NULL)
1107
0
        goto Fail;
1108
1109
0
    for (;;) {
1110
0
        PyObject *op2;
1111
1112
0
        if (!_PyObject_IsUniquelyReferenced(args)) {
1113
0
            Py_DECREF(args);
1114
0
            if ((args = PyTuple_New(2)) == NULL)
1115
0
                goto Fail;
1116
0
        }
1117
1118
0
        op2 = PyIter_Next(it);
1119
0
        if (op2 == NULL) {
1120
0
            if (PyErr_Occurred())
1121
0
                goto Fail;
1122
0
            break;
1123
0
        }
1124
1125
0
        if (result == NULL)
1126
0
            result = op2;
1127
0
        else {
1128
            /* Update the args tuple in-place */
1129
0
            assert(Py_REFCNT(args) == 1);
1130
0
            Py_XSETREF(_PyTuple_ITEMS(args)[0], result);
1131
0
            Py_XSETREF(_PyTuple_ITEMS(args)[1], op2);
1132
0
            if ((result = PyObject_Call(func, args, NULL)) == NULL) {
1133
0
                goto Fail;
1134
0
            }
1135
            // bpo-42536: The GC may have untracked this args tuple. Since we're
1136
            // recycling it, make sure it's tracked again:
1137
0
            _PyTuple_Recycle(args);
1138
0
        }
1139
0
    }
1140
1141
0
    Py_DECREF(args);
1142
1143
0
    if (result == NULL)
1144
0
        PyErr_SetString(PyExc_TypeError,
1145
0
                        "reduce() of empty iterable with no initial value");
1146
1147
0
    Py_DECREF(it);
1148
0
    return result;
1149
1150
0
Fail:
1151
0
    Py_XDECREF(args);
1152
0
    Py_XDECREF(result);
1153
0
    Py_DECREF(it);
1154
0
    return NULL;
1155
0
}
1156
1157
/* lru_cache object **********************************************************/
1158
1159
/* There are four principal algorithmic differences from the pure python version:
1160
1161
   1). The C version relies on the GIL instead of having its own reentrant lock.
1162
1163
   2). The prev/next link fields use borrowed references.
1164
1165
   3). For a full cache, the pure python version rotates the location of the
1166
       root entry so that it never has to move individual links and it can
1167
       limit updates to just the key and result fields.  However, in the C
1168
       version, links are temporarily removed while the cache dict updates are
1169
       occurring. Afterwards, they are appended or prepended back into the
1170
       doubly-linked lists.
1171
1172
   4)  In the Python version, the _HashSeq class is used to prevent __hash__
1173
       from being called more than once.  In the C version, the "known hash"
1174
       variants of dictionary calls as used to the same effect.
1175
1176
*/
1177
1178
struct lru_list_elem;
1179
struct lru_cache_object;
1180
1181
typedef struct lru_list_elem {
1182
    PyObject_HEAD
1183
    struct lru_list_elem *prev, *next;  /* borrowed links */
1184
    Py_hash_t hash;
1185
    PyObject *key, *result;
1186
} lru_list_elem;
1187
1188
0
#define lru_list_elem_CAST(op)  ((lru_list_elem *)(op))
1189
1190
static void
1191
lru_list_elem_dealloc(PyObject *op)
1192
0
{
1193
0
    lru_list_elem *link = lru_list_elem_CAST(op);
1194
0
    PyTypeObject *tp = Py_TYPE(link);
1195
0
    Py_XDECREF(link->key);
1196
0
    Py_XDECREF(link->result);
1197
0
    tp->tp_free(link);
1198
0
    Py_DECREF(tp);
1199
0
}
1200
1201
static PyType_Slot lru_list_elem_type_slots[] = {
1202
    {Py_tp_dealloc, lru_list_elem_dealloc},
1203
    {0, 0}
1204
};
1205
1206
static PyType_Spec lru_list_elem_type_spec = {
1207
    .name = "functools._lru_list_elem",
1208
    .basicsize = sizeof(lru_list_elem),
1209
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
1210
             Py_TPFLAGS_IMMUTABLETYPE,
1211
    .slots = lru_list_elem_type_slots
1212
};
1213
1214
1215
typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
1216
1217
typedef struct lru_cache_object {
1218
    lru_list_elem root;  /* includes PyObject_HEAD */
1219
    lru_cache_ternaryfunc wrapper;
1220
    int typed;
1221
    PyObject *cache;
1222
    Py_ssize_t hits;
1223
    PyObject *func;
1224
    Py_ssize_t maxsize;
1225
    Py_ssize_t misses;
1226
    /* the kwd_mark is used delimit args and keywords in the cache keys */
1227
    PyObject *kwd_mark;
1228
    PyTypeObject *lru_list_elem_type;
1229
    PyObject *cache_info_type;
1230
    PyObject *dict;
1231
    PyObject *weakreflist;
1232
} lru_cache_object;
1233
1234
43.4k
#define lru_cache_object_CAST(op)   ((lru_cache_object *)(op))
1235
1236
static PyObject *
1237
lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
1238
                   PyObject *kwds, int typed)
1239
37.0k
{
1240
37.0k
    PyObject *key, *keyword, *value;
1241
37.0k
    Py_ssize_t key_size, pos, key_pos, kwds_size;
1242
1243
37.0k
    kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
1244
1245
    /* short path, key will match args anyway, which is a tuple */
1246
37.0k
    if (!typed && !kwds_size) {
1247
36.9k
        if (PyTuple_GET_SIZE(args) == 1) {
1248
553
            key = PyTuple_GET_ITEM(args, 0);
1249
553
            if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) {
1250
                /* For common scalar keys, save space by
1251
                   dropping the enclosing args tuple  */
1252
533
                return Py_NewRef(key);
1253
533
            }
1254
553
        }
1255
36.4k
        return Py_NewRef(args);
1256
36.9k
    }
1257
1258
80
    key_size = PyTuple_GET_SIZE(args);
1259
80
    if (kwds_size)
1260
0
        key_size += kwds_size * 2 + 1;
1261
80
    if (typed)
1262
80
        key_size += PyTuple_GET_SIZE(args) + kwds_size;
1263
1264
80
    key = PyTuple_New(key_size);
1265
80
    if (key == NULL)
1266
0
        return NULL;
1267
1268
80
    key_pos = 0;
1269
512
    for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
1270
432
        PyObject *item = PyTuple_GET_ITEM(args, pos);
1271
432
        PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
1272
432
    }
1273
80
    if (kwds_size) {
1274
0
        PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(kwd_mark));
1275
0
        for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
1276
0
            PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(keyword));
1277
0
            PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(value));
1278
0
        }
1279
0
        assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
1280
0
    }
1281
80
    if (typed) {
1282
512
        for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
1283
432
            PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
1284
432
            PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
1285
432
        }
1286
80
        if (kwds_size) {
1287
0
            for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
1288
0
                PyObject *item = (PyObject *)Py_TYPE(value);
1289
0
                PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
1290
0
            }
1291
0
        }
1292
80
    }
1293
80
    assert(key_pos == key_size);
1294
80
    return key;
1295
80
}
1296
1297
static PyObject *
1298
uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
1299
0
{
1300
0
    PyObject *result;
1301
1302
0
    FT_ATOMIC_ADD_SSIZE(self->misses, 1);
1303
0
    result = PyObject_Call(self->func, args, kwds);
1304
0
    if (!result)
1305
0
        return NULL;
1306
0
    return result;
1307
0
}
1308
1309
static PyObject *
1310
infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
1311
188
{
1312
188
    PyObject *result;
1313
188
    Py_hash_t hash;
1314
188
    PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
1315
188
    if (!key)
1316
0
        return NULL;
1317
188
    hash = PyObject_Hash(key);
1318
188
    if (hash == -1) {
1319
0
        Py_DECREF(key);
1320
0
        return NULL;
1321
0
    }
1322
188
    int res = _PyDict_GetItemRef_KnownHash((PyDictObject *)self->cache, key, hash, &result);
1323
188
    if (res > 0) {
1324
95
        FT_ATOMIC_ADD_SSIZE(self->hits, 1);
1325
95
        Py_DECREF(key);
1326
95
        return result;
1327
95
    }
1328
93
    if (res < 0) {
1329
0
        Py_DECREF(key);
1330
0
        return NULL;
1331
0
    }
1332
93
    FT_ATOMIC_ADD_SSIZE(self->misses, 1);
1333
93
    result = PyObject_Call(self->func, args, kwds);
1334
93
    if (!result) {
1335
0
        Py_DECREF(key);
1336
0
        return NULL;
1337
0
    }
1338
93
    if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
1339
0
        Py_DECREF(result);
1340
0
        Py_DECREF(key);
1341
0
        return NULL;
1342
0
    }
1343
93
    Py_DECREF(key);
1344
93
    return result;
1345
93
}
1346
1347
static void
1348
lru_cache_extract_link(lru_list_elem *link)
1349
35.6k
{
1350
35.6k
    lru_list_elem *link_prev = link->prev;
1351
35.6k
    lru_list_elem *link_next = link->next;
1352
35.6k
    link_prev->next = link->next;
1353
35.6k
    link_next->prev = link->prev;
1354
35.6k
}
1355
1356
static void
1357
lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
1358
36.8k
{
1359
36.8k
    lru_list_elem *root = &self->root;
1360
36.8k
    lru_list_elem *last = root->prev;
1361
36.8k
    last->next = root->prev = link;
1362
36.8k
    link->prev = last;
1363
36.8k
    link->next = root;
1364
36.8k
}
1365
1366
static void
1367
lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
1368
0
{
1369
0
    lru_list_elem *root = &self->root;
1370
0
    lru_list_elem *first = root->next;
1371
0
    first->prev = root->next = link;
1372
0
    link->prev = root;
1373
0
    link->next = first;
1374
0
}
1375
1376
/* General note on reentrancy:
1377
1378
   There are four dictionary calls in the bounded_lru_cache_wrapper():
1379
   1) The initial check for a cache match.  2) The post user-function
1380
   check for a cache match.  3) The deletion of the oldest entry.
1381
   4) The addition of the newest entry.
1382
1383
   In all four calls, we have a known hash which lets use avoid a call
1384
   to __hash__().  That leaves only __eq__ as a possible source of a
1385
   reentrant call.
1386
1387
   The __eq__ method call is always made for a cache hit (dict access #1).
1388
   Accordingly, we have make sure not modify the cache state prior to
1389
   this call.
1390
1391
   The __eq__ method call is never made for the deletion (dict access #3)
1392
   because it is an identity match.
1393
1394
   For the other two accesses (#2 and #4), calls to __eq__ only occur
1395
   when some other entry happens to have an exactly matching hash (all
1396
   64-bits).  Though rare, this can happen, so we have to make sure to
1397
   either call it at the top of its code path before any cache
1398
   state modifications (dict access #2) or be prepared to restore
1399
   invariants at the end of the code path (dict access #4).
1400
1401
   Another possible source of reentrancy is a decref which can trigger
1402
   arbitrary code execution.  To make the code easier to reason about,
1403
   the decrefs are deferred to the end of the each possible code path
1404
   so that we know the cache is a consistent state.
1405
 */
1406
1407
static int
1408
bounded_lru_cache_get_lock_held(lru_cache_object *self, PyObject *args, PyObject *kwds,
1409
                                PyObject **result, PyObject **key, Py_hash_t *hash)
1410
36.8k
{
1411
36.8k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
1412
36.8k
    lru_list_elem *link;
1413
1414
36.8k
    PyObject *key_ = *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
1415
36.8k
    if (!key_)
1416
0
        return -1;
1417
36.8k
    Py_hash_t hash_ = *hash = PyObject_Hash(key_);
1418
36.8k
    if (hash_ == -1) {
1419
0
        Py_DECREF(key_);  /* dead reference left in *key, is not used */
1420
0
        return -1;
1421
0
    }
1422
36.8k
    int res = _PyDict_GetItemRef_KnownHash_LockHeld((PyDictObject *)self->cache, key_, hash_,
1423
36.8k
                                                    (PyObject **)&link);
1424
36.8k
    if (res > 0) {
1425
35.6k
        lru_cache_extract_link(link);
1426
35.6k
        lru_cache_append_link(self, link);
1427
35.6k
        *result = link->result;
1428
35.6k
        FT_ATOMIC_ADD_SSIZE(self->hits, 1);
1429
35.6k
        Py_INCREF(link->result);
1430
35.6k
        Py_DECREF(link);
1431
35.6k
        Py_DECREF(key_);
1432
35.6k
        return 1;
1433
35.6k
    }
1434
1.25k
    if (res < 0) {
1435
0
        Py_DECREF(key_);
1436
0
        return -1;
1437
0
    }
1438
1.25k
    FT_ATOMIC_ADD_SSIZE(self->misses, 1);
1439
1.25k
    return 0;
1440
1.25k
}
1441
1442
static PyObject *
1443
bounded_lru_cache_update_lock_held(lru_cache_object *self,
1444
                                   PyObject *result, PyObject *key, Py_hash_t hash)
1445
1.25k
{
1446
1.25k
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
1447
1.25k
    lru_list_elem *link;
1448
1.25k
    PyObject *testresult;
1449
1.25k
    int res;
1450
1451
1.25k
    if (!result) {
1452
0
        Py_DECREF(key);
1453
0
        return NULL;
1454
0
    }
1455
1.25k
    res = _PyDict_GetItemRef_KnownHash_LockHeld((PyDictObject *)self->cache, key, hash,
1456
1.25k
                                                &testresult);
1457
1.25k
    if (res > 0) {
1458
        /* Getting here means that this same key was added to the cache
1459
           during the PyObject_Call().  Since the link update is already
1460
           done, we need only return the computed result. */
1461
0
        Py_DECREF(testresult);
1462
0
        Py_DECREF(key);
1463
0
        return result;
1464
0
    }
1465
1.25k
    if (res < 0) {
1466
        /* This is an unusual case since this same lookup
1467
           did not previously trigger an error during lookup.
1468
           Treat it the same as an error in user function
1469
           and return with the error set. */
1470
0
        Py_DECREF(key);
1471
0
        Py_DECREF(result);
1472
0
        return NULL;
1473
0
    }
1474
    /* This is the normal case.  The new key wasn't found before
1475
       user function call and it is still not there.  So we
1476
       proceed normally and update the cache with the new result. */
1477
1478
1.25k
    assert(self->maxsize > 0);
1479
1.25k
    if (PyDict_GET_SIZE(self->cache) < self->maxsize ||
1480
0
        self->root.next == &self->root)
1481
1.25k
    {
1482
        /* Cache is not full, so put the result in a new link */
1483
1.25k
        link = (lru_list_elem *)PyObject_New(lru_list_elem,
1484
1.25k
                                             self->lru_list_elem_type);
1485
1.25k
        if (link == NULL) {
1486
0
            Py_DECREF(key);
1487
0
            Py_DECREF(result);
1488
0
            return NULL;
1489
0
        }
1490
1491
1.25k
        link->hash = hash;
1492
1.25k
        link->key = key;
1493
1.25k
        link->result = result;
1494
        /* What is really needed here is a SetItem variant with a "no clobber"
1495
           option.  If the __eq__ call triggers a reentrant call that adds
1496
           this same key, then this setitem call will update the cache dict
1497
           with this new link, leaving the old link as an orphan (i.e. not
1498
           having a cache dict entry that refers to it). */
1499
1.25k
        if (_PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)self->cache, key,
1500
1.25k
                                               (PyObject *)link, hash) < 0) {
1501
0
            Py_DECREF(link);
1502
0
            return NULL;
1503
0
        }
1504
1.25k
        lru_cache_append_link(self, link);
1505
1.25k
        return Py_NewRef(result);
1506
1.25k
    }
1507
    /* Since the cache is full, we need to evict an old key and add
1508
       a new key.  Rather than free the old link and allocate a new
1509
       one, we reuse the link for the new key and result and move it
1510
       to front of the cache to mark it as recently used.
1511
1512
       We try to assure all code paths (including errors) leave all
1513
       of the links in place.  Either the link is successfully
1514
       updated and moved or it is restored to its old position.
1515
       However if an unrecoverable error is found, it doesn't
1516
       make sense to reinsert the link, so we leave it out
1517
       and the cache will no longer register as full.
1518
    */
1519
0
    PyObject *oldkey, *oldresult, *popresult;
1520
1521
    /* Extract the oldest item. */
1522
0
    assert(self->root.next != &self->root);
1523
0
    link = self->root.next;
1524
0
    lru_cache_extract_link(link);
1525
    /* Remove it from the cache.
1526
       The cache dict holds one reference to the link.
1527
       We created one other reference when the link was created.
1528
       The linked list only has borrowed references. */
1529
0
    res = _PyDict_Pop_KnownHash((PyDictObject*)self->cache, link->key,
1530
0
                                link->hash, &popresult);
1531
0
    if (res < 0) {
1532
        /* An error arose while trying to remove the oldest key (the one
1533
           being evicted) from the cache.  We restore the link to its
1534
           original position as the oldest link.  Then we allow the
1535
           error propagate upward; treating it the same as an error
1536
           arising in the user function. */
1537
0
        lru_cache_prepend_link(self, link);
1538
0
        Py_DECREF(key);
1539
0
        Py_DECREF(result);
1540
0
        return NULL;
1541
0
    }
1542
0
    if (res == 0) {
1543
        /* Getting here means that the user function call or another
1544
           thread has already removed the old key from the dictionary.
1545
           This link is now an orphan.  Since we don't want to leave the
1546
           cache in an inconsistent state, we don't restore the link. */
1547
0
        assert(popresult == NULL);
1548
0
        Py_DECREF(link);
1549
0
        Py_DECREF(key);
1550
0
        return result;
1551
0
    }
1552
1553
    /* Keep a reference to the old key and old result to prevent their
1554
       ref counts from going to zero during the update. That will
1555
       prevent potentially arbitrary object clean-up code (i.e. __del__)
1556
       from running while we're still adjusting the links. */
1557
0
    assert(popresult != NULL);
1558
0
    oldkey = link->key;
1559
0
    oldresult = link->result;
1560
1561
0
    link->hash = hash;
1562
0
    link->key = key;
1563
0
    link->result = result;
1564
    /* Note:  The link is being added to the cache dict without the
1565
       prev and next fields set to valid values.   We have to wait
1566
       for successful insertion in the cache dict before adding the
1567
       link to the linked list.  Otherwise, the potentially reentrant
1568
       __eq__ call could cause the then orphan link to be visited. */
1569
0
    if (_PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)self->cache, key,
1570
0
                                           (PyObject *)link, hash) < 0) {
1571
        /* Somehow the cache dict update failed.  We no longer can
1572
           restore the old link.  Let the error propagate upward and
1573
           leave the cache short one link. */
1574
0
        Py_DECREF(popresult);
1575
0
        Py_DECREF(link);
1576
0
        Py_DECREF(oldkey);
1577
0
        Py_DECREF(oldresult);
1578
0
        return NULL;
1579
0
    }
1580
0
    lru_cache_append_link(self, link);
1581
0
    Py_INCREF(result); /* for return */
1582
0
    Py_DECREF(popresult);
1583
0
    Py_DECREF(oldkey);
1584
0
    Py_DECREF(oldresult);
1585
0
    return result;
1586
0
}
1587
1588
static PyObject *
1589
bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
1590
36.8k
{
1591
36.8k
    PyObject *key, *result;
1592
36.8k
    Py_hash_t hash;
1593
36.8k
    int res;
1594
1595
36.8k
    Py_BEGIN_CRITICAL_SECTION(self);
1596
36.8k
    res = bounded_lru_cache_get_lock_held(self, args, kwds, &result, &key, &hash);
1597
36.8k
    Py_END_CRITICAL_SECTION();
1598
1599
36.8k
    if (res < 0) {
1600
0
        return NULL;
1601
0
    }
1602
36.8k
    if (res > 0) {
1603
35.6k
        return result;
1604
35.6k
    }
1605
1606
1.25k
    result = PyObject_Call(self->func, args, kwds);
1607
1608
1.25k
    Py_BEGIN_CRITICAL_SECTION(self);
1609
    /* Note:  key will be stolen in the below function, and
1610
       result may be stolen or sometimes re-returned as a passthrough.
1611
       Treat both as being stolen.
1612
     */
1613
1.25k
    result = bounded_lru_cache_update_lock_held(self, result, key, hash);
1614
1.25k
    Py_END_CRITICAL_SECTION();
1615
1616
1.25k
    return result;
1617
36.8k
}
1618
1619
static PyObject *
1620
lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
1621
276
{
1622
276
    PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
1623
276
    int typed;
1624
276
    lru_cache_object *obj;
1625
276
    Py_ssize_t maxsize;
1626
276
    PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
1627
276
    _functools_state *state;
1628
276
    static char *keywords[] = {"user_function", "maxsize", "typed",
1629
276
                               "cache_info_type", NULL};
1630
1631
276
    if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
1632
276
                                     &func, &maxsize_O, &typed,
1633
276
                                     &cache_info_type)) {
1634
0
        return NULL;
1635
0
    }
1636
1637
276
    if (!PyCallable_Check(func)) {
1638
0
        PyErr_SetString(PyExc_TypeError,
1639
0
                        "the first argument must be callable");
1640
0
        return NULL;
1641
0
    }
1642
1643
276
    state = get_functools_state_by_type(type);
1644
276
    if (state == NULL) {
1645
0
        return NULL;
1646
0
    }
1647
1648
    /* select the caching function, and make/inc maxsize_O */
1649
276
    if (maxsize_O == Py_None) {
1650
29
        wrapper = infinite_lru_cache_wrapper;
1651
        /* use this only to initialize lru_cache_object attribute maxsize */
1652
29
        maxsize = -1;
1653
247
    } else if (PyIndex_Check(maxsize_O)) {
1654
247
        maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1655
247
        if (maxsize == -1 && PyErr_Occurred())
1656
0
            return NULL;
1657
247
        if (maxsize < 0) {
1658
0
            maxsize = 0;
1659
0
        }
1660
247
        if (maxsize == 0)
1661
0
            wrapper = uncached_lru_cache_wrapper;
1662
247
        else
1663
247
            wrapper = bounded_lru_cache_wrapper;
1664
247
    } else {
1665
0
        PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1666
0
        return NULL;
1667
0
    }
1668
1669
276
    if (!(cachedict = PyDict_New()))
1670
0
        return NULL;
1671
1672
276
    obj = (lru_cache_object *)type->tp_alloc(type, 0);
1673
276
    if (obj == NULL) {
1674
0
        Py_DECREF(cachedict);
1675
0
        return NULL;
1676
0
    }
1677
1678
276
    obj->root.prev = &obj->root;
1679
276
    obj->root.next = &obj->root;
1680
276
    obj->wrapper = wrapper;
1681
276
    obj->typed = typed;
1682
276
    obj->cache = cachedict;
1683
276
    obj->func = Py_NewRef(func);
1684
276
    obj->misses = obj->hits = 0;
1685
276
    obj->maxsize = maxsize;
1686
276
    obj->kwd_mark = Py_NewRef(state->kwd_mark);
1687
276
    obj->lru_list_elem_type = (PyTypeObject*)Py_NewRef(state->lru_list_elem_type);
1688
276
    obj->cache_info_type = Py_NewRef(cache_info_type);
1689
276
    obj->dict = NULL;
1690
276
    obj->weakreflist = NULL;
1691
276
    return (PyObject *)obj;
1692
276
}
1693
1694
static lru_list_elem *
1695
lru_cache_unlink_list(lru_cache_object *self)
1696
5.66k
{
1697
5.66k
    lru_list_elem *root = &self->root;
1698
5.66k
    lru_list_elem *link = root->next;
1699
5.66k
    if (link == root)
1700
5.66k
        return NULL;
1701
0
    root->prev->next = NULL;
1702
0
    root->next = root->prev = root;
1703
0
    return link;
1704
5.66k
}
1705
1706
static void
1707
lru_cache_clear_list(lru_list_elem *link)
1708
5.66k
{
1709
5.66k
    while (link != NULL) {
1710
0
        lru_list_elem *next = link->next;
1711
0
        Py_SETREF(link, next);
1712
0
    }
1713
5.66k
}
1714
1715
static int
1716
lru_cache_tp_clear(PyObject *op)
1717
0
{
1718
0
    lru_cache_object *self = lru_cache_object_CAST(op);
1719
0
    lru_list_elem *list = lru_cache_unlink_list(self);
1720
0
    Py_CLEAR(self->cache);
1721
0
    Py_CLEAR(self->func);
1722
0
    Py_CLEAR(self->kwd_mark);
1723
0
    Py_CLEAR(self->lru_list_elem_type);
1724
0
    Py_CLEAR(self->cache_info_type);
1725
0
    Py_CLEAR(self->dict);
1726
0
    lru_cache_clear_list(list);
1727
0
    return 0;
1728
0
}
1729
1730
static void
1731
lru_cache_dealloc(PyObject *op)
1732
0
{
1733
0
    lru_cache_object *obj = lru_cache_object_CAST(op);
1734
0
    PyTypeObject *tp = Py_TYPE(obj);
1735
    /* bpo-31095: UnTrack is needed before calling any callbacks */
1736
0
    PyObject_GC_UnTrack(obj);
1737
0
    FT_CLEAR_WEAKREFS(op, obj->weakreflist);
1738
1739
0
    (void)lru_cache_tp_clear(op);
1740
0
    tp->tp_free(obj);
1741
0
    Py_DECREF(tp);
1742
0
}
1743
1744
static PyObject *
1745
lru_cache_call(PyObject *op, PyObject *args, PyObject *kwds)
1746
37.0k
{
1747
37.0k
    lru_cache_object *self = lru_cache_object_CAST(op);
1748
37.0k
    PyObject *result;
1749
37.0k
    result = self->wrapper(self, args, kwds);
1750
37.0k
    return result;
1751
37.0k
}
1752
1753
static PyObject *
1754
lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1755
20
{
1756
20
    if (obj == Py_None || obj == NULL) {
1757
20
        return Py_NewRef(self);
1758
20
    }
1759
0
    return PyMethod_New(self, obj);
1760
20
}
1761
1762
/*[clinic input]
1763
@critical_section
1764
_functools._lru_cache_wrapper.cache_info
1765
1766
Report cache statistics
1767
[clinic start generated code]*/
1768
1769
static PyObject *
1770
_functools__lru_cache_wrapper_cache_info_impl(PyObject *self)
1771
/*[clinic end generated code: output=cc796a0b06dbd717 input=00e1acb31aa21ecc]*/
1772
0
{
1773
0
    lru_cache_object *_self = (lru_cache_object *) self;
1774
0
    if (_self->maxsize == -1) {
1775
0
        return PyObject_CallFunction(_self->cache_info_type, "nnOn",
1776
0
                                     FT_ATOMIC_LOAD_SSIZE_RELAXED(_self->hits),
1777
0
                                     FT_ATOMIC_LOAD_SSIZE_RELAXED(_self->misses),
1778
0
                                     Py_None,
1779
0
                                     PyDict_GET_SIZE(_self->cache));
1780
0
    }
1781
0
    return PyObject_CallFunction(_self->cache_info_type, "nnnn",
1782
0
                                 FT_ATOMIC_LOAD_SSIZE_RELAXED(_self->hits),
1783
0
                                 FT_ATOMIC_LOAD_SSIZE_RELAXED(_self->misses),
1784
0
                                 _self->maxsize,
1785
0
                                 PyDict_GET_SIZE(_self->cache));
1786
0
}
1787
1788
/*[clinic input]
1789
@critical_section
1790
_functools._lru_cache_wrapper.cache_clear
1791
1792
Clear the cache and cache statistics
1793
[clinic start generated code]*/
1794
1795
static PyObject *
1796
_functools__lru_cache_wrapper_cache_clear_impl(PyObject *self)
1797
/*[clinic end generated code: output=58423b35efc3e381 input=dfa33acbecf8b4b2]*/
1798
5.66k
{
1799
5.66k
    lru_cache_object *_self = (lru_cache_object *) self;
1800
5.66k
    lru_list_elem *list = lru_cache_unlink_list(_self);
1801
5.66k
    FT_ATOMIC_STORE_SSIZE_RELAXED(_self->hits, 0);
1802
5.66k
    FT_ATOMIC_STORE_SSIZE_RELAXED(_self->misses, 0);
1803
5.66k
    if (_self->wrapper == bounded_lru_cache_wrapper) {
1804
        /* The critical section on the lru cache itself protects the dictionary
1805
           for bounded_lru_cache instances. */
1806
5.66k
        _PyDict_Clear_LockHeld(_self->cache);
1807
5.66k
    } else {
1808
0
        PyDict_Clear(_self->cache);
1809
0
    }
1810
5.66k
    lru_cache_clear_list(list);
1811
5.66k
    Py_RETURN_NONE;
1812
5.66k
}
1813
1814
static PyObject *
1815
lru_cache_reduce(PyObject *self, PyObject *Py_UNUSED(dummy))
1816
0
{
1817
0
    return PyObject_GetAttrString(self, "__qualname__");
1818
0
}
1819
1820
/*[clinic input]
1821
_functools._lru_cache_wrapper.__copy__
1822
1823
Return a copy of the wrapper, which is the wrapper itself.
1824
[clinic start generated code]*/
1825
1826
static PyObject *
1827
_functools__lru_cache_wrapper___copy___impl(PyObject *self)
1828
/*[clinic end generated code: output=d681851615d57391 input=41d000bde05efb2b]*/
1829
0
{
1830
0
    return Py_NewRef(self);
1831
0
}
1832
1833
/*[clinic input]
1834
_functools._lru_cache_wrapper.__deepcopy__
1835
1836
    memo: object
1837
    /
1838
1839
Return a deep copy of the wrapper, which is the wrapper itself.
1840
[clinic start generated code]*/
1841
1842
static PyObject *
1843
_functools__lru_cache_wrapper___deepcopy__(PyObject *self, PyObject *memo)
1844
/*[clinic end generated code: output=3445cd9d96273c9e input=84f706565f55ce46]*/
1845
0
{
1846
0
    return Py_NewRef(self);
1847
0
}
1848
1849
static int
1850
lru_cache_tp_traverse(PyObject *op, visitproc visit, void *arg)
1851
6.39k
{
1852
6.39k
    lru_cache_object *self = lru_cache_object_CAST(op);
1853
6.39k
    Py_VISIT(Py_TYPE(self));
1854
6.39k
    lru_list_elem *link = self->root.next;
1855
10.7k
    while (link != &self->root) {
1856
4.32k
        lru_list_elem *next = link->next;
1857
4.32k
        Py_VISIT(link->key);
1858
4.32k
        Py_VISIT(link->result);
1859
4.32k
        Py_VISIT(Py_TYPE(link));
1860
4.32k
        link = next;
1861
4.32k
    }
1862
6.39k
    Py_VISIT(self->cache);
1863
6.39k
    Py_VISIT(self->func);
1864
6.39k
    Py_VISIT(self->kwd_mark);
1865
6.39k
    Py_VISIT(self->lru_list_elem_type);
1866
6.39k
    Py_VISIT(self->cache_info_type);
1867
6.39k
    Py_VISIT(self->dict);
1868
6.39k
    return 0;
1869
6.39k
}
1870
1871
1872
PyDoc_STRVAR(lru_cache_doc,
1873
"Create a cached callable that wraps another function.\n\
1874
\n\
1875
user_function:      the function being cached\n\
1876
\n\
1877
maxsize:  0         for no caching\n\
1878
          None      for unlimited cache size\n\
1879
          n         for a bounded cache\n\
1880
\n\
1881
typed:    False     cache f(3) and f(3.0) as identical calls\n\
1882
          True      cache f(3) and f(3.0) as distinct calls\n\
1883
\n\
1884
cache_info_type:    namedtuple class with the fields:\n\
1885
                        hits misses currsize maxsize\n"
1886
);
1887
1888
static PyMethodDef lru_cache_methods[] = {
1889
    _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_INFO_METHODDEF
1890
    _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_CLEAR_METHODDEF
1891
    {"__reduce__", lru_cache_reduce, METH_NOARGS},
1892
    _FUNCTOOLS__LRU_CACHE_WRAPPER___COPY___METHODDEF
1893
    _FUNCTOOLS__LRU_CACHE_WRAPPER___DEEPCOPY___METHODDEF
1894
    {NULL}
1895
};
1896
1897
static PyGetSetDef lru_cache_getsetlist[] = {
1898
    {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1899
    {NULL}
1900
};
1901
1902
static PyMemberDef lru_cache_memberlist[] = {
1903
    {"__dictoffset__", Py_T_PYSSIZET,
1904
     offsetof(lru_cache_object, dict), Py_READONLY},
1905
    {"__weaklistoffset__", Py_T_PYSSIZET,
1906
     offsetof(lru_cache_object, weakreflist), Py_READONLY},
1907
    {NULL}  /* Sentinel */
1908
};
1909
1910
static PyType_Slot lru_cache_type_slots[] = {
1911
    {Py_tp_dealloc, lru_cache_dealloc},
1912
    {Py_tp_call, lru_cache_call},
1913
    {Py_tp_doc, (void *)lru_cache_doc},
1914
    {Py_tp_traverse, lru_cache_tp_traverse},
1915
    {Py_tp_clear, lru_cache_tp_clear},
1916
    {Py_tp_methods, lru_cache_methods},
1917
    {Py_tp_members, lru_cache_memberlist},
1918
    {Py_tp_getset, lru_cache_getsetlist},
1919
    {Py_tp_descr_get, lru_cache_descr_get},
1920
    {Py_tp_new, lru_cache_new},
1921
    {0, 0}
1922
};
1923
1924
static PyType_Spec lru_cache_type_spec = {
1925
    .name = "functools._lru_cache_wrapper",
1926
    .basicsize = sizeof(lru_cache_object),
1927
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1928
             Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_IMMUTABLETYPE,
1929
    .slots = lru_cache_type_slots
1930
};
1931
1932
1933
/* module level code ********************************************************/
1934
1935
PyDoc_STRVAR(_functools_doc,
1936
"Tools that operate on functions.");
1937
1938
static PyMethodDef _functools_methods[] = {
1939
    _FUNCTOOLS_REDUCE_METHODDEF
1940
    _FUNCTOOLS_CMP_TO_KEY_METHODDEF
1941
    {NULL,              NULL}           /* sentinel */
1942
};
1943
1944
static int
1945
_functools_exec(PyObject *module)
1946
28
{
1947
28
    _functools_state *state = get_functools_state(module);
1948
28
    state->kwd_mark = _PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type);
1949
28
    if (state->kwd_mark == NULL) {
1950
0
        return -1;
1951
0
    }
1952
1953
28
    state->placeholder_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1954
28
        &placeholder_type_spec, NULL);
1955
28
    if (state->placeholder_type == NULL) {
1956
0
        return -1;
1957
0
    }
1958
28
    if (PyModule_AddType(module, state->placeholder_type) < 0) {
1959
0
        return -1;
1960
0
    }
1961
1962
28
    PyObject *placeholder = PyObject_CallNoArgs((PyObject *)state->placeholder_type);
1963
28
    if (placeholder == NULL) {
1964
0
        return -1;
1965
0
    }
1966
28
    if (PyModule_AddObjectRef(module, "Placeholder", placeholder) < 0) {
1967
0
        Py_DECREF(placeholder);
1968
0
        return -1;
1969
0
    }
1970
28
    Py_DECREF(placeholder);
1971
1972
28
    state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1973
28
        &partial_type_spec, NULL);
1974
28
    if (state->partial_type == NULL) {
1975
0
        return -1;
1976
0
    }
1977
28
    if (PyModule_AddType(module, state->partial_type) < 0) {
1978
0
        return -1;
1979
0
    }
1980
1981
28
    PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
1982
28
        &lru_cache_type_spec, NULL);
1983
28
    if (lru_cache_type == NULL) {
1984
0
        return -1;
1985
0
    }
1986
28
    if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
1987
0
        Py_DECREF(lru_cache_type);
1988
0
        return -1;
1989
0
    }
1990
28
    Py_DECREF(lru_cache_type);
1991
1992
28
    state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1993
28
        &keyobject_type_spec, NULL);
1994
28
    if (state->keyobject_type == NULL) {
1995
0
        return -1;
1996
0
    }
1997
    // keyobject_type is used only internally.
1998
    // So we don't expose it in module namespace.
1999
2000
28
    state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
2001
28
        module, &lru_list_elem_type_spec, NULL);
2002
28
    if (state->lru_list_elem_type == NULL) {
2003
0
        return -1;
2004
0
    }
2005
    // lru_list_elem is used only in _lru_cache_wrapper.
2006
    // So we don't expose it in module namespace.
2007
2008
28
    return 0;
2009
28
}
2010
2011
static int
2012
_functools_traverse(PyObject *module, visitproc visit, void *arg)
2013
1.58k
{
2014
1.58k
    _functools_state *state = get_functools_state(module);
2015
1.58k
    Py_VISIT(state->kwd_mark);
2016
1.58k
    Py_VISIT(state->placeholder_type);
2017
1.58k
    Py_VISIT(state->placeholder);
2018
1.58k
    Py_VISIT(state->partial_type);
2019
1.58k
    Py_VISIT(state->keyobject_type);
2020
1.58k
    Py_VISIT(state->lru_list_elem_type);
2021
1.58k
    return 0;
2022
1.58k
}
2023
2024
static int
2025
_functools_clear(PyObject *module)
2026
0
{
2027
0
    _functools_state *state = get_functools_state(module);
2028
0
    Py_CLEAR(state->kwd_mark);
2029
0
    Py_CLEAR(state->placeholder_type);
2030
0
    Py_CLEAR(state->placeholder);
2031
0
    Py_CLEAR(state->partial_type);
2032
0
    Py_CLEAR(state->keyobject_type);
2033
0
    Py_CLEAR(state->lru_list_elem_type);
2034
0
    return 0;
2035
0
}
2036
2037
static void
2038
_functools_free(void *module)
2039
0
{
2040
0
    (void)_functools_clear((PyObject *)module);
2041
0
}
2042
2043
static struct PyModuleDef_Slot _functools_slots[] = {
2044
    _Py_ABI_SLOT,
2045
    {Py_mod_exec, _functools_exec},
2046
    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
2047
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
2048
    {0, NULL}
2049
};
2050
2051
static struct PyModuleDef _functools_module = {
2052
    PyModuleDef_HEAD_INIT,
2053
    .m_name = "_functools",
2054
    .m_doc = _functools_doc,
2055
    .m_size = sizeof(_functools_state),
2056
    .m_methods = _functools_methods,
2057
    .m_slots = _functools_slots,
2058
    .m_traverse = _functools_traverse,
2059
    .m_clear = _functools_clear,
2060
    .m_free = _functools_free,
2061
};
2062
2063
PyMODINIT_FUNC
2064
PyInit__functools(void)
2065
28
{
2066
28
    return PyModuleDef_Init(&_functools_module);
2067
28
}