Coverage Report

Created: 2025-08-26 06:26

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