Coverage Report

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