Coverage Report

Created: 2025-07-11 06:24

/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.19k
{
40
4.19k
    void *state = _PyModule_GetState(module);
41
4.19k
    assert(state != NULL);
42
4.19k
    return (_functools_state *)state;
43
4.19k
}
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
11
{
91
11
    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
11
    _functools_state *state = get_functools_state_by_type(type);
96
11
    if (state->placeholder != NULL) {
97
0
        return Py_NewRef(state->placeholder);
98
0
    }
99
100
11
    PyObject *placeholder = PyType_GenericNew(type, NULL, NULL);
101
11
    if (placeholder == NULL) {
102
0
        return NULL;
103
0
    }
104
105
11
    if (state->placeholder == NULL) {
106
11
        state->placeholder = Py_NewRef(placeholder);
107
11
    }
108
11
    return placeholder;
109
11
}
110
111
static int
112
placeholder_traverse(PyObject *self, visitproc visit, void *arg)
113
4.10k
{
114
4.10k
    Py_VISIT(Py_TYPE(self));
115
4.10k
    return 0;
116
4.10k
}
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
36.1k
#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
82
{
159
82
    PyObject *module = PyType_GetModuleByDef(type, &_functools_module);
160
82
    if (module == NULL) {
161
0
        return NULL;
162
0
    }
163
82
    return get_functools_state(module);
164
82
}
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
20
{
170
20
    PyObject *func, *pto_args, *new_args, *pto_kw, *phold;
171
20
    partialobject *pto;
172
20
    Py_ssize_t pto_phcount = 0;
173
20
    Py_ssize_t new_nargs = PyTuple_GET_SIZE(args) - 1;
174
175
20
    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
20
    func = PyTuple_GET_ITEM(args, 0);
181
20
    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
20
    _functools_state *state = get_functools_state_by_type(type);
188
20
    if (state == NULL) {
189
0
        return NULL;
190
0
    }
191
20
    phold = state->placeholder;
192
193
    /* Placeholder restrictions */
194
20
    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
20
    if (kw != NULL) {
202
14
        PyObject *key, *val;
203
14
        Py_ssize_t pos = 0;
204
56
        while (PyDict_Next(kw, &pos, &key, &val)) {
205
42
            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
42
        }
211
14
    }
212
213
    /* check wrapped function / object */
214
20
    pto_args = pto_kw = NULL;
215
20
    int res = PyObject_TypeCheck(func, state->partial_type);
216
20
    if (res == -1) {
217
0
        return NULL;
218
0
    }
219
20
    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
20
    pto = (partialobject *)type->tp_alloc(type, 0);
234
20
    if (pto == NULL)
235
0
        return NULL;
236
237
20
    pto->fn = Py_NewRef(func);
238
20
    pto->placeholder = phold;
239
240
20
    new_args = PyTuple_GetSlice(args, 1, new_nargs + 1);
241
20
    if (new_args == NULL) {
242
0
        Py_DECREF(pto);
243
0
        return NULL;
244
0
    }
245
246
    /* Count placeholders */
247
20
    Py_ssize_t phcount = 0;
248
20
    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
20
    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
20
    else if (pto_args == NULL) {
283
20
        pto->args = new_args;
284
20
        pto->phcount = phcount;
285
20
    }
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
20
    if (pto_kw == NULL || PyDict_GET_SIZE(pto_kw) == 0) {
298
20
        if (kw == NULL) {
299
6
            pto->kw = PyDict_New();
300
6
        }
301
14
        else if (Py_REFCNT(kw) == 1) {
302
14
            pto->kw = Py_NewRef(kw);
303
14
        }
304
0
        else {
305
0
            pto->kw = PyDict_Copy(kw);
306
0
        }
307
20
    }
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
20
    if (pto->kw == NULL) {
318
0
        Py_DECREF(pto);
319
0
        return NULL;
320
0
    }
321
322
20
    partial_setvectorcall(pto);
323
20
    return (PyObject *)pto;
324
20
}
325
326
static int
327
partial_clear(PyObject *self)
328
14
{
329
14
    partialobject *pto = partialobject_CAST(self);
330
14
    Py_CLEAR(pto->fn);
331
14
    Py_CLEAR(pto->args);
332
14
    Py_CLEAR(pto->kw);
333
14
    Py_CLEAR(pto->dict);
334
14
    return 0;
335
14
}
336
337
static int
338
partial_traverse(PyObject *self, visitproc visit, void *arg)
339
3.63k
{
340
3.63k
    partialobject *pto = partialobject_CAST(self);
341
3.63k
    Py_VISIT(Py_TYPE(pto));
342
3.63k
    Py_VISIT(pto->fn);
343
3.63k
    Py_VISIT(pto->args);
344
3.63k
    Py_VISIT(pto->kw);
345
3.63k
    Py_VISIT(pto->dict);
346
3.63k
    return 0;
347
3.63k
}
348
349
static void
350
partial_dealloc(PyObject *self)
351
14
{
352
14
    PyTypeObject *tp = Py_TYPE(self);
353
    /* bpo-31095: UnTrack is needed before calling any callbacks */
354
14
    PyObject_GC_UnTrack(self);
355
14
    FT_CLEAR_WEAKREFS(self, partialobject_CAST(self)->weakreflist);
356
14
    (void)partial_clear(self);
357
14
    tp->tp_free(self);
358
14
    Py_DECREF(tp);
359
14
}
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
32.4k
{
374
32.4k
    partialobject *pto = partialobject_CAST(self);;
375
32.4k
    PyThreadState *tstate = _PyThreadState_GET();
376
32.4k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
377
378
    /* Placeholder check */
379
32.4k
    Py_ssize_t pto_phcount = pto->phcount;
380
32.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
32.4k
    PyObject **pto_args = _PyTuple_ITEMS(pto->args);
388
32.4k
    Py_ssize_t pto_nargs = PyTuple_GET_SIZE(pto->args);
389
32.4k
    Py_ssize_t pto_nkwds = PyDict_GET_SIZE(pto->kw);
390
32.4k
    Py_ssize_t nkwds = kwnames == NULL ? 0 : PyTuple_GET_SIZE(kwnames);
391
32.4k
    Py_ssize_t nargskw = nargs + nkwds;
392
393
    /* Special cases */
394
32.4k
    if (!pto_nkwds) {
395
        /* Fast path if we're called without arguments */
396
32.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
32.4k
        if (pto_nargs == 1 && (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET)) {
404
32.4k
            PyObject **newargs = (PyObject **)args - 1;
405
32.4k
            PyObject *tmp = newargs[0];
406
32.4k
            newargs[0] = pto_args[0];
407
32.4k
            PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn, newargs,
408
32.4k
                                                       nargs + 1, kwnames);
409
32.4k
            newargs[0] = tmp;
410
32.4k
            return ret;
411
32.4k
        }
412
32.4k
    }
413
414
    /* Total sizes */
415
14
    Py_ssize_t tot_nargs = pto_nargs + nargs - pto_phcount;
416
14
    Py_ssize_t tot_nkwds = pto_nkwds + nkwds;
417
14
    Py_ssize_t tot_nargskw = tot_nargs + tot_nkwds;
418
419
14
    PyObject *pto_kw_merged = NULL;  // pto_kw with duplicates merged (if any)
420
14
    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
14
    PyObject *small_stack[_PY_FASTCALL_SMALL_STACK * 2];
428
14
    PyObject **tmp_stack, **stack;
429
14
    Py_ssize_t init_stack_size = tot_nargskw;
430
14
    if (pto_nkwds) {
431
        // If pto_nkwds, allocate additional space for temporary new keys
432
14
        init_stack_size += nkwds;
433
14
    }
434
14
    if (init_stack_size <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
435
14
        stack = small_stack;
436
14
    }
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
14
    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
14
    else {
453
        /* stack is now         [<positionals>, <pto_kwds>, <kwds>, <kwds_keys>]
454
         * Will resize later to [<positionals>, <merged_kwds>] */
455
14
        PyObject *key, *val;
456
457
        /* Merge kw to pto_kw or add to tail (if not duplicate) */
458
14
        Py_ssize_t n_tail = 0;
459
14
        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
14
        Py_ssize_t n_merges = nkwds - n_tail;
482
483
        /* Create total kwnames */
484
14
        tot_kwnames = PyTuple_New(tot_nkwds - n_merges);
485
14
        if (tot_kwnames == NULL) {
486
0
            Py_XDECREF(pto_kw_merged);
487
0
            goto error;
488
0
        }
489
14
        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
14
        Py_ssize_t pos = 0, i = 0;
497
56
        while (PyDict_Next(n_merges ? pto_kw_merged : pto->kw, &pos, &key, &val)) {
498
42
            assert(i < pto_nkwds);
499
42
            PyTuple_SET_ITEM(tot_kwnames, i, Py_NewRef(key));
500
42
            stack[tot_nargs + i] = val;
501
42
            i++;
502
42
        }
503
14
        assert(i == pto_nkwds);
504
14
        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
14
        Py_ssize_t noveralloc = n_merges + nkwds;
509
14
        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
14
    }
521
522
    /* Copy Positionals to stack */
523
14
    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
14
    else {
541
14
        memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
542
14
        memcpy(stack + pto_nargs, args, nargs * sizeof(PyObject*));
543
14
    }
544
545
14
    PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn, stack,
546
14
                                               tot_nargs, tot_kwnames);
547
14
    if (stack != small_stack) {
548
0
        PyMem_Free(stack);
549
0
    }
550
14
    if (pto_nkwds) {
551
14
        Py_DECREF(tot_kwnames);
552
14
    }
553
14
    return ret;
554
555
0
 error:
556
0
    if (stack != small_stack) {
557
0
        PyMem_Free(stack);
558
0
    }
559
0
    return NULL;
560
14
}
561
562
/* Set pto->vectorcall depending on the parameters of the partial object */
563
static void
564
partial_setvectorcall(partialobject *pto)
565
20
{
566
20
    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
20
    else {
574
20
        pto->vectorcall = partial_vectorcall;
575
20
    }
576
20
}
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
_functools.reduce
1043
1044
    function as func: object
1045
    iterable as seq: object
1046
    /
1047
    initial as result: object = NULL
1048
1049
Apply a function of two arguments cumulatively to the items of an iterable, from left to right.
1050
1051
This effectively reduces the iterable to a single value.  If initial is present,
1052
it is placed before the items of the iterable in the calculation, and serves as
1053
a default when the iterable is empty.
1054
1055
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
1056
calculates ((((1 + 2) + 3) + 4) + 5).
1057
[clinic start generated code]*/
1058
1059
static PyObject *
1060
_functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq,
1061
                       PyObject *result)
1062
/*[clinic end generated code: output=30d898fe1267c79d input=1511e9a8c38581ac]*/
1063
0
{
1064
0
    PyObject *args, *it;
1065
1066
0
    if (result != NULL)
1067
0
        Py_INCREF(result);
1068
1069
0
    it = PyObject_GetIter(seq);
1070
0
    if (it == NULL) {
1071
0
        if (PyErr_ExceptionMatches(PyExc_TypeError))
1072
0
            PyErr_SetString(PyExc_TypeError,
1073
0
                            "reduce() arg 2 must support iteration");
1074
0
        Py_XDECREF(result);
1075
0
        return NULL;
1076
0
    }
1077
1078
0
    if ((args = PyTuple_New(2)) == NULL)
1079
0
        goto Fail;
1080
1081
0
    for (;;) {
1082
0
        PyObject *op2;
1083
1084
0
        if (Py_REFCNT(args) > 1) {
1085
0
            Py_DECREF(args);
1086
0
            if ((args = PyTuple_New(2)) == NULL)
1087
0
                goto Fail;
1088
0
        }
1089
1090
0
        op2 = PyIter_Next(it);
1091
0
        if (op2 == NULL) {
1092
0
            if (PyErr_Occurred())
1093
0
                goto Fail;
1094
0
            break;
1095
0
        }
1096
1097
0
        if (result == NULL)
1098
0
            result = op2;
1099
0
        else {
1100
            /* Update the args tuple in-place */
1101
0
            assert(Py_REFCNT(args) == 1);
1102
0
            Py_XSETREF(_PyTuple_ITEMS(args)[0], result);
1103
0
            Py_XSETREF(_PyTuple_ITEMS(args)[1], op2);
1104
0
            if ((result = PyObject_Call(func, args, NULL)) == NULL) {
1105
0
                goto Fail;
1106
0
            }
1107
            // bpo-42536: The GC may have untracked this args tuple. Since we're
1108
            // recycling it, make sure it's tracked again:
1109
0
            _PyTuple_Recycle(args);
1110
0
        }
1111
0
    }
1112
1113
0
    Py_DECREF(args);
1114
1115
0
    if (result == NULL)
1116
0
        PyErr_SetString(PyExc_TypeError,
1117
0
                        "reduce() of empty iterable with no initial value");
1118
1119
0
    Py_DECREF(it);
1120
0
    return result;
1121
1122
0
Fail:
1123
0
    Py_XDECREF(args);
1124
0
    Py_XDECREF(result);
1125
0
    Py_DECREF(it);
1126
0
    return NULL;
1127
0
}
1128
1129
/* lru_cache object **********************************************************/
1130
1131
/* There are four principal algorithmic differences from the pure python version:
1132
1133
   1). The C version relies on the GIL instead of having its own reentrant lock.
1134
1135
   2). The prev/next link fields use borrowed references.
1136
1137
   3). For a full cache, the pure python version rotates the location of the
1138
       root entry so that it never has to move individual links and it can
1139
       limit updates to just the key and result fields.  However, in the C
1140
       version, links are temporarily removed while the cache dict updates are
1141
       occurring. Afterwards, they are appended or prepended back into the
1142
       doubly-linked lists.
1143
1144
   4)  In the Python version, the _HashSeq class is used to prevent __hash__
1145
       from being called more than once.  In the C version, the "known hash"
1146
       variants of dictionary calls as used to the same effect.
1147
1148
*/
1149
1150
struct lru_list_elem;
1151
struct lru_cache_object;
1152
1153
typedef struct lru_list_elem {
1154
    PyObject_HEAD
1155
    struct lru_list_elem *prev, *next;  /* borrowed links */
1156
    Py_hash_t hash;
1157
    PyObject *key, *result;
1158
} lru_list_elem;
1159
1160
0
#define lru_list_elem_CAST(op)  ((lru_list_elem *)(op))
1161
1162
static void
1163
lru_list_elem_dealloc(PyObject *op)
1164
0
{
1165
0
    lru_list_elem *link = lru_list_elem_CAST(op);
1166
0
    PyTypeObject *tp = Py_TYPE(link);
1167
0
    Py_XDECREF(link->key);
1168
0
    Py_XDECREF(link->result);
1169
0
    tp->tp_free(link);
1170
0
    Py_DECREF(tp);
1171
0
}
1172
1173
static PyType_Slot lru_list_elem_type_slots[] = {
1174
    {Py_tp_dealloc, lru_list_elem_dealloc},
1175
    {0, 0}
1176
};
1177
1178
static PyType_Spec lru_list_elem_type_spec = {
1179
    .name = "functools._lru_list_elem",
1180
    .basicsize = sizeof(lru_list_elem),
1181
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
1182
             Py_TPFLAGS_IMMUTABLETYPE,
1183
    .slots = lru_list_elem_type_slots
1184
};
1185
1186
1187
typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
1188
1189
typedef struct lru_cache_object {
1190
    lru_list_elem root;  /* includes PyObject_HEAD */
1191
    lru_cache_ternaryfunc wrapper;
1192
    int typed;
1193
    PyObject *cache;
1194
    Py_ssize_t hits;
1195
    PyObject *func;
1196
    Py_ssize_t maxsize;
1197
    Py_ssize_t misses;
1198
    /* the kwd_mark is used delimit args and keywords in the cache keys */
1199
    PyObject *kwd_mark;
1200
    PyTypeObject *lru_list_elem_type;
1201
    PyObject *cache_info_type;
1202
    PyObject *dict;
1203
    PyObject *weakreflist;
1204
} lru_cache_object;
1205
1206
31.6k
#define lru_cache_object_CAST(op)   ((lru_cache_object *)(op))
1207
1208
static PyObject *
1209
lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
1210
                   PyObject *kwds, int typed)
1211
0
{
1212
0
    PyObject *key, *keyword, *value;
1213
0
    Py_ssize_t key_size, pos, key_pos, kwds_size;
1214
1215
0
    kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
1216
1217
    /* short path, key will match args anyway, which is a tuple */
1218
0
    if (!typed && !kwds_size) {
1219
0
        if (PyTuple_GET_SIZE(args) == 1) {
1220
0
            key = PyTuple_GET_ITEM(args, 0);
1221
0
            if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) {
1222
                /* For common scalar keys, save space by
1223
                   dropping the enclosing args tuple  */
1224
0
                return Py_NewRef(key);
1225
0
            }
1226
0
        }
1227
0
        return Py_NewRef(args);
1228
0
    }
1229
1230
0
    key_size = PyTuple_GET_SIZE(args);
1231
0
    if (kwds_size)
1232
0
        key_size += kwds_size * 2 + 1;
1233
0
    if (typed)
1234
0
        key_size += PyTuple_GET_SIZE(args) + kwds_size;
1235
1236
0
    key = PyTuple_New(key_size);
1237
0
    if (key == NULL)
1238
0
        return NULL;
1239
1240
0
    key_pos = 0;
1241
0
    for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
1242
0
        PyObject *item = PyTuple_GET_ITEM(args, pos);
1243
0
        PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
1244
0
    }
1245
0
    if (kwds_size) {
1246
0
        PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(kwd_mark));
1247
0
        for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
1248
0
            PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(keyword));
1249
0
            PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(value));
1250
0
        }
1251
0
        assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
1252
0
    }
1253
0
    if (typed) {
1254
0
        for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
1255
0
            PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
1256
0
            PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
1257
0
        }
1258
0
        if (kwds_size) {
1259
0
            for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
1260
0
                PyObject *item = (PyObject *)Py_TYPE(value);
1261
0
                PyTuple_SET_ITEM(key, key_pos++, Py_NewRef(item));
1262
0
            }
1263
0
        }
1264
0
    }
1265
0
    assert(key_pos == key_size);
1266
0
    return key;
1267
0
}
1268
1269
static PyObject *
1270
uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
1271
0
{
1272
0
    PyObject *result;
1273
1274
0
    FT_ATOMIC_ADD_SSIZE(self->misses, 1);
1275
0
    result = PyObject_Call(self->func, args, kwds);
1276
0
    if (!result)
1277
0
        return NULL;
1278
0
    return result;
1279
0
}
1280
1281
static PyObject *
1282
infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
1283
0
{
1284
0
    PyObject *result;
1285
0
    Py_hash_t hash;
1286
0
    PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
1287
0
    if (!key)
1288
0
        return NULL;
1289
0
    hash = PyObject_Hash(key);
1290
0
    if (hash == -1) {
1291
0
        Py_DECREF(key);
1292
0
        return NULL;
1293
0
    }
1294
0
    int res = _PyDict_GetItemRef_KnownHash((PyDictObject *)self->cache, key, hash, &result);
1295
0
    if (res > 0) {
1296
0
        FT_ATOMIC_ADD_SSIZE(self->hits, 1);
1297
0
        Py_DECREF(key);
1298
0
        return result;
1299
0
    }
1300
0
    if (res < 0) {
1301
0
        Py_DECREF(key);
1302
0
        return NULL;
1303
0
    }
1304
0
    FT_ATOMIC_ADD_SSIZE(self->misses, 1);
1305
0
    result = PyObject_Call(self->func, args, kwds);
1306
0
    if (!result) {
1307
0
        Py_DECREF(key);
1308
0
        return NULL;
1309
0
    }
1310
0
    if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
1311
0
        Py_DECREF(result);
1312
0
        Py_DECREF(key);
1313
0
        return NULL;
1314
0
    }
1315
0
    Py_DECREF(key);
1316
0
    return result;
1317
0
}
1318
1319
static void
1320
lru_cache_extract_link(lru_list_elem *link)
1321
0
{
1322
0
    lru_list_elem *link_prev = link->prev;
1323
0
    lru_list_elem *link_next = link->next;
1324
0
    link_prev->next = link->next;
1325
0
    link_next->prev = link->prev;
1326
0
}
1327
1328
static void
1329
lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
1330
0
{
1331
0
    lru_list_elem *root = &self->root;
1332
0
    lru_list_elem *last = root->prev;
1333
0
    last->next = root->prev = link;
1334
0
    link->prev = last;
1335
0
    link->next = root;
1336
0
}
1337
1338
static void
1339
lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
1340
0
{
1341
0
    lru_list_elem *root = &self->root;
1342
0
    lru_list_elem *first = root->next;
1343
0
    first->prev = root->next = link;
1344
0
    link->prev = root;
1345
0
    link->next = first;
1346
0
}
1347
1348
/* General note on reentrancy:
1349
1350
   There are four dictionary calls in the bounded_lru_cache_wrapper():
1351
   1) The initial check for a cache match.  2) The post user-function
1352
   check for a cache match.  3) The deletion of the oldest entry.
1353
   4) The addition of the newest entry.
1354
1355
   In all four calls, we have a known hash which lets use avoid a call
1356
   to __hash__().  That leaves only __eq__ as a possible source of a
1357
   reentrant call.
1358
1359
   The __eq__ method call is always made for a cache hit (dict access #1).
1360
   Accordingly, we have make sure not modify the cache state prior to
1361
   this call.
1362
1363
   The __eq__ method call is never made for the deletion (dict access #3)
1364
   because it is an identity match.
1365
1366
   For the other two accesses (#2 and #4), calls to __eq__ only occur
1367
   when some other entry happens to have an exactly matching hash (all
1368
   64-bits).  Though rare, this can happen, so we have to make sure to
1369
   either call it at the top of its code path before any cache
1370
   state modifications (dict access #2) or be prepared to restore
1371
   invariants at the end of the code path (dict access #4).
1372
1373
   Another possible source of reentrancy is a decref which can trigger
1374
   arbitrary code execution.  To make the code easier to reason about,
1375
   the decrefs are deferred to the end of the each possible code path
1376
   so that we know the cache is a consistent state.
1377
 */
1378
1379
static int
1380
bounded_lru_cache_get_lock_held(lru_cache_object *self, PyObject *args, PyObject *kwds,
1381
                                PyObject **result, PyObject **key, Py_hash_t *hash)
1382
0
{
1383
0
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
1384
0
    lru_list_elem *link;
1385
1386
0
    PyObject *key_ = *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
1387
0
    if (!key_)
1388
0
        return -1;
1389
0
    Py_hash_t hash_ = *hash = PyObject_Hash(key_);
1390
0
    if (hash_ == -1) {
1391
0
        Py_DECREF(key_);  /* dead reference left in *key, is not used */
1392
0
        return -1;
1393
0
    }
1394
0
    int res = _PyDict_GetItemRef_KnownHash_LockHeld((PyDictObject *)self->cache, key_, hash_,
1395
0
                                                    (PyObject **)&link);
1396
0
    if (res > 0) {
1397
0
        lru_cache_extract_link(link);
1398
0
        lru_cache_append_link(self, link);
1399
0
        *result = link->result;
1400
0
        FT_ATOMIC_ADD_SSIZE(self->hits, 1);
1401
0
        Py_INCREF(link->result);
1402
0
        Py_DECREF(link);
1403
0
        Py_DECREF(key_);
1404
0
        return 1;
1405
0
    }
1406
0
    if (res < 0) {
1407
0
        Py_DECREF(key_);
1408
0
        return -1;
1409
0
    }
1410
0
    FT_ATOMIC_ADD_SSIZE(self->misses, 1);
1411
0
    return 0;
1412
0
}
1413
1414
static PyObject *
1415
bounded_lru_cache_update_lock_held(lru_cache_object *self,
1416
                                   PyObject *result, PyObject *key, Py_hash_t hash)
1417
0
{
1418
0
    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
1419
0
    lru_list_elem *link;
1420
0
    PyObject *testresult;
1421
0
    int res;
1422
1423
0
    if (!result) {
1424
0
        Py_DECREF(key);
1425
0
        return NULL;
1426
0
    }
1427
0
    res = _PyDict_GetItemRef_KnownHash_LockHeld((PyDictObject *)self->cache, key, hash,
1428
0
                                                &testresult);
1429
0
    if (res > 0) {
1430
        /* Getting here means that this same key was added to the cache
1431
           during the PyObject_Call().  Since the link update is already
1432
           done, we need only return the computed result. */
1433
0
        Py_DECREF(testresult);
1434
0
        Py_DECREF(key);
1435
0
        return result;
1436
0
    }
1437
0
    if (res < 0) {
1438
        /* This is an unusual case since this same lookup
1439
           did not previously trigger an error during lookup.
1440
           Treat it the same as an error in user function
1441
           and return with the error set. */
1442
0
        Py_DECREF(key);
1443
0
        Py_DECREF(result);
1444
0
        return NULL;
1445
0
    }
1446
    /* This is the normal case.  The new key wasn't found before
1447
       user function call and it is still not there.  So we
1448
       proceed normally and update the cache with the new result. */
1449
1450
0
    assert(self->maxsize > 0);
1451
0
    if (PyDict_GET_SIZE(self->cache) < self->maxsize ||
1452
0
        self->root.next == &self->root)
1453
0
    {
1454
        /* Cache is not full, so put the result in a new link */
1455
0
        link = (lru_list_elem *)PyObject_New(lru_list_elem,
1456
0
                                             self->lru_list_elem_type);
1457
0
        if (link == NULL) {
1458
0
            Py_DECREF(key);
1459
0
            Py_DECREF(result);
1460
0
            return NULL;
1461
0
        }
1462
1463
0
        link->hash = hash;
1464
0
        link->key = key;
1465
0
        link->result = result;
1466
        /* What is really needed here is a SetItem variant with a "no clobber"
1467
           option.  If the __eq__ call triggers a reentrant call that adds
1468
           this same key, then this setitem call will update the cache dict
1469
           with this new link, leaving the old link as an orphan (i.e. not
1470
           having a cache dict entry that refers to it). */
1471
0
        if (_PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)self->cache, key,
1472
0
                                               (PyObject *)link, hash) < 0) {
1473
0
            Py_DECREF(link);
1474
0
            return NULL;
1475
0
        }
1476
0
        lru_cache_append_link(self, link);
1477
0
        return Py_NewRef(result);
1478
0
    }
1479
    /* Since the cache is full, we need to evict an old key and add
1480
       a new key.  Rather than free the old link and allocate a new
1481
       one, we reuse the link for the new key and result and move it
1482
       to front of the cache to mark it as recently used.
1483
1484
       We try to assure all code paths (including errors) leave all
1485
       of the links in place.  Either the link is successfully
1486
       updated and moved or it is restored to its old position.
1487
       However if an unrecoverable error is found, it doesn't
1488
       make sense to reinsert the link, so we leave it out
1489
       and the cache will no longer register as full.
1490
    */
1491
0
    PyObject *oldkey, *oldresult, *popresult;
1492
1493
    /* Extract the oldest item. */
1494
0
    assert(self->root.next != &self->root);
1495
0
    link = self->root.next;
1496
0
    lru_cache_extract_link(link);
1497
    /* Remove it from the cache.
1498
       The cache dict holds one reference to the link.
1499
       We created one other reference when the link was created.
1500
       The linked list only has borrowed references. */
1501
0
    res = _PyDict_Pop_KnownHash((PyDictObject*)self->cache, link->key,
1502
0
                                link->hash, &popresult);
1503
0
    if (res < 0) {
1504
        /* An error arose while trying to remove the oldest key (the one
1505
           being evicted) from the cache.  We restore the link to its
1506
           original position as the oldest link.  Then we allow the
1507
           error propagate upward; treating it the same as an error
1508
           arising in the user function. */
1509
0
        lru_cache_prepend_link(self, link);
1510
0
        Py_DECREF(key);
1511
0
        Py_DECREF(result);
1512
0
        return NULL;
1513
0
    }
1514
0
    if (res == 0) {
1515
        /* Getting here means that the user function call or another
1516
           thread has already removed the old key from the dictionary.
1517
           This link is now an orphan.  Since we don't want to leave the
1518
           cache in an inconsistent state, we don't restore the link. */
1519
0
        assert(popresult == NULL);
1520
0
        Py_DECREF(link);
1521
0
        Py_DECREF(key);
1522
0
        return result;
1523
0
    }
1524
1525
    /* Keep a reference to the old key and old result to prevent their
1526
       ref counts from going to zero during the update. That will
1527
       prevent potentially arbitrary object clean-up code (i.e. __del__)
1528
       from running while we're still adjusting the links. */
1529
0
    assert(popresult != NULL);
1530
0
    oldkey = link->key;
1531
0
    oldresult = link->result;
1532
1533
0
    link->hash = hash;
1534
0
    link->key = key;
1535
0
    link->result = result;
1536
    /* Note:  The link is being added to the cache dict without the
1537
       prev and next fields set to valid values.   We have to wait
1538
       for successful insertion in the cache dict before adding the
1539
       link to the linked list.  Otherwise, the potentially reentrant
1540
       __eq__ call could cause the then orphan link to be visited. */
1541
0
    if (_PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)self->cache, key,
1542
0
                                           (PyObject *)link, hash) < 0) {
1543
        /* Somehow the cache dict update failed.  We no longer can
1544
           restore the old link.  Let the error propagate upward and
1545
           leave the cache short one link. */
1546
0
        Py_DECREF(popresult);
1547
0
        Py_DECREF(link);
1548
0
        Py_DECREF(oldkey);
1549
0
        Py_DECREF(oldresult);
1550
0
        return NULL;
1551
0
    }
1552
0
    lru_cache_append_link(self, link);
1553
0
    Py_INCREF(result); /* for return */
1554
0
    Py_DECREF(popresult);
1555
0
    Py_DECREF(oldkey);
1556
0
    Py_DECREF(oldresult);
1557
0
    return result;
1558
0
}
1559
1560
static PyObject *
1561
bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
1562
0
{
1563
0
    PyObject *key, *result;
1564
0
    Py_hash_t hash;
1565
0
    int res;
1566
1567
0
    Py_BEGIN_CRITICAL_SECTION(self);
1568
0
    res = bounded_lru_cache_get_lock_held(self, args, kwds, &result, &key, &hash);
1569
0
    Py_END_CRITICAL_SECTION();
1570
1571
0
    if (res < 0) {
1572
0
        return NULL;
1573
0
    }
1574
0
    if (res > 0) {
1575
0
        return result;
1576
0
    }
1577
1578
0
    result = PyObject_Call(self->func, args, kwds);
1579
1580
0
    Py_BEGIN_CRITICAL_SECTION(self);
1581
    /* Note:  key will be stolen in the below function, and
1582
       result may be stolen or sometimes re-returned as a passthrough.
1583
       Treat both as being stolen.
1584
     */
1585
0
    result = bounded_lru_cache_update_lock_held(self, result, key, hash);
1586
0
    Py_END_CRITICAL_SECTION();
1587
1588
0
    return result;
1589
0
}
1590
1591
static PyObject *
1592
lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
1593
51
{
1594
51
    PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
1595
51
    int typed;
1596
51
    lru_cache_object *obj;
1597
51
    Py_ssize_t maxsize;
1598
51
    PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
1599
51
    _functools_state *state;
1600
51
    static char *keywords[] = {"user_function", "maxsize", "typed",
1601
51
                               "cache_info_type", NULL};
1602
1603
51
    if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
1604
51
                                     &func, &maxsize_O, &typed,
1605
51
                                     &cache_info_type)) {
1606
0
        return NULL;
1607
0
    }
1608
1609
51
    if (!PyCallable_Check(func)) {
1610
0
        PyErr_SetString(PyExc_TypeError,
1611
0
                        "the first argument must be callable");
1612
0
        return NULL;
1613
0
    }
1614
1615
51
    state = get_functools_state_by_type(type);
1616
51
    if (state == NULL) {
1617
0
        return NULL;
1618
0
    }
1619
1620
    /* select the caching function, and make/inc maxsize_O */
1621
51
    if (maxsize_O == Py_None) {
1622
0
        wrapper = infinite_lru_cache_wrapper;
1623
        /* use this only to initialize lru_cache_object attribute maxsize */
1624
0
        maxsize = -1;
1625
51
    } else if (PyIndex_Check(maxsize_O)) {
1626
51
        maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
1627
51
        if (maxsize == -1 && PyErr_Occurred())
1628
0
            return NULL;
1629
51
        if (maxsize < 0) {
1630
0
            maxsize = 0;
1631
0
        }
1632
51
        if (maxsize == 0)
1633
0
            wrapper = uncached_lru_cache_wrapper;
1634
51
        else
1635
51
            wrapper = bounded_lru_cache_wrapper;
1636
51
    } else {
1637
0
        PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
1638
0
        return NULL;
1639
0
    }
1640
1641
51
    if (!(cachedict = PyDict_New()))
1642
0
        return NULL;
1643
1644
51
    obj = (lru_cache_object *)type->tp_alloc(type, 0);
1645
51
    if (obj == NULL) {
1646
0
        Py_DECREF(cachedict);
1647
0
        return NULL;
1648
0
    }
1649
1650
51
    obj->root.prev = &obj->root;
1651
51
    obj->root.next = &obj->root;
1652
51
    obj->wrapper = wrapper;
1653
51
    obj->typed = typed;
1654
51
    obj->cache = cachedict;
1655
51
    obj->func = Py_NewRef(func);
1656
51
    obj->misses = obj->hits = 0;
1657
51
    obj->maxsize = maxsize;
1658
51
    obj->kwd_mark = Py_NewRef(state->kwd_mark);
1659
51
    obj->lru_list_elem_type = (PyTypeObject*)Py_NewRef(state->lru_list_elem_type);
1660
51
    obj->cache_info_type = Py_NewRef(cache_info_type);
1661
51
    obj->dict = NULL;
1662
51
    obj->weakreflist = NULL;
1663
51
    return (PyObject *)obj;
1664
51
}
1665
1666
static lru_list_elem *
1667
lru_cache_unlink_list(lru_cache_object *self)
1668
0
{
1669
0
    lru_list_elem *root = &self->root;
1670
0
    lru_list_elem *link = root->next;
1671
0
    if (link == root)
1672
0
        return NULL;
1673
0
    root->prev->next = NULL;
1674
0
    root->next = root->prev = root;
1675
0
    return link;
1676
0
}
1677
1678
static void
1679
lru_cache_clear_list(lru_list_elem *link)
1680
0
{
1681
0
    while (link != NULL) {
1682
0
        lru_list_elem *next = link->next;
1683
0
        Py_SETREF(link, next);
1684
0
    }
1685
0
}
1686
1687
static int
1688
lru_cache_tp_clear(PyObject *op)
1689
0
{
1690
0
    lru_cache_object *self = lru_cache_object_CAST(op);
1691
0
    lru_list_elem *list = lru_cache_unlink_list(self);
1692
0
    Py_CLEAR(self->cache);
1693
0
    Py_CLEAR(self->func);
1694
0
    Py_CLEAR(self->kwd_mark);
1695
0
    Py_CLEAR(self->lru_list_elem_type);
1696
0
    Py_CLEAR(self->cache_info_type);
1697
0
    Py_CLEAR(self->dict);
1698
0
    lru_cache_clear_list(list);
1699
0
    return 0;
1700
0
}
1701
1702
static void
1703
lru_cache_dealloc(PyObject *op)
1704
0
{
1705
0
    lru_cache_object *obj = lru_cache_object_CAST(op);
1706
0
    PyTypeObject *tp = Py_TYPE(obj);
1707
    /* bpo-31095: UnTrack is needed before calling any callbacks */
1708
0
    PyObject_GC_UnTrack(obj);
1709
0
    FT_CLEAR_WEAKREFS(op, obj->weakreflist);
1710
1711
0
    (void)lru_cache_tp_clear(op);
1712
0
    tp->tp_free(obj);
1713
0
    Py_DECREF(tp);
1714
0
}
1715
1716
static PyObject *
1717
lru_cache_call(PyObject *op, PyObject *args, PyObject *kwds)
1718
0
{
1719
0
    lru_cache_object *self = lru_cache_object_CAST(op);
1720
0
    PyObject *result;
1721
0
    result = self->wrapper(self, args, kwds);
1722
0
    return result;
1723
0
}
1724
1725
static PyObject *
1726
lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1727
0
{
1728
0
    if (obj == Py_None || obj == NULL) {
1729
0
        return Py_NewRef(self);
1730
0
    }
1731
0
    return PyMethod_New(self, obj);
1732
0
}
1733
1734
/*[clinic input]
1735
@critical_section
1736
_functools._lru_cache_wrapper.cache_info
1737
1738
Report cache statistics
1739
[clinic start generated code]*/
1740
1741
static PyObject *
1742
_functools__lru_cache_wrapper_cache_info_impl(PyObject *self)
1743
/*[clinic end generated code: output=cc796a0b06dbd717 input=00e1acb31aa21ecc]*/
1744
0
{
1745
0
    lru_cache_object *_self = (lru_cache_object *) self;
1746
0
    if (_self->maxsize == -1) {
1747
0
        return PyObject_CallFunction(_self->cache_info_type, "nnOn",
1748
0
                                     FT_ATOMIC_LOAD_SSIZE_RELAXED(_self->hits),
1749
0
                                     FT_ATOMIC_LOAD_SSIZE_RELAXED(_self->misses),
1750
0
                                     Py_None,
1751
0
                                     PyDict_GET_SIZE(_self->cache));
1752
0
    }
1753
0
    return PyObject_CallFunction(_self->cache_info_type, "nnnn",
1754
0
                                 FT_ATOMIC_LOAD_SSIZE_RELAXED(_self->hits),
1755
0
                                 FT_ATOMIC_LOAD_SSIZE_RELAXED(_self->misses),
1756
0
                                 _self->maxsize,
1757
0
                                 PyDict_GET_SIZE(_self->cache));
1758
0
}
1759
1760
/*[clinic input]
1761
@critical_section
1762
_functools._lru_cache_wrapper.cache_clear
1763
1764
Clear the cache and cache statistics
1765
[clinic start generated code]*/
1766
1767
static PyObject *
1768
_functools__lru_cache_wrapper_cache_clear_impl(PyObject *self)
1769
/*[clinic end generated code: output=58423b35efc3e381 input=dfa33acbecf8b4b2]*/
1770
0
{
1771
0
    lru_cache_object *_self = (lru_cache_object *) self;
1772
0
    lru_list_elem *list = lru_cache_unlink_list(_self);
1773
0
    FT_ATOMIC_STORE_SSIZE_RELAXED(_self->hits, 0);
1774
0
    FT_ATOMIC_STORE_SSIZE_RELAXED(_self->misses, 0);
1775
0
    if (_self->wrapper == bounded_lru_cache_wrapper) {
1776
        /* The critical section on the lru cache itself protects the dictionary
1777
           for bounded_lru_cache instances. */
1778
0
        _PyDict_Clear_LockHeld(_self->cache);
1779
0
    } else {
1780
0
        PyDict_Clear(_self->cache);
1781
0
    }
1782
0
    lru_cache_clear_list(list);
1783
0
    Py_RETURN_NONE;
1784
0
}
1785
1786
static PyObject *
1787
lru_cache_reduce(PyObject *self, PyObject *Py_UNUSED(dummy))
1788
0
{
1789
0
    return PyObject_GetAttrString(self, "__qualname__");
1790
0
}
1791
1792
static PyObject *
1793
lru_cache_copy(PyObject *self, PyObject *Py_UNUSED(args))
1794
0
{
1795
0
    return Py_NewRef(self);
1796
0
}
1797
1798
static PyObject *
1799
lru_cache_deepcopy(PyObject *self, PyObject *Py_UNUSED(args))
1800
0
{
1801
0
    return Py_NewRef(self);
1802
0
}
1803
1804
static int
1805
lru_cache_tp_traverse(PyObject *op, visitproc visit, void *arg)
1806
31.6k
{
1807
31.6k
    lru_cache_object *self = lru_cache_object_CAST(op);
1808
31.6k
    Py_VISIT(Py_TYPE(self));
1809
31.6k
    lru_list_elem *link = self->root.next;
1810
31.6k
    while (link != &self->root) {
1811
0
        lru_list_elem *next = link->next;
1812
0
        Py_VISIT(link->key);
1813
0
        Py_VISIT(link->result);
1814
0
        Py_VISIT(Py_TYPE(link));
1815
0
        link = next;
1816
0
    }
1817
31.6k
    Py_VISIT(self->cache);
1818
31.6k
    Py_VISIT(self->func);
1819
31.6k
    Py_VISIT(self->kwd_mark);
1820
31.6k
    Py_VISIT(self->lru_list_elem_type);
1821
31.6k
    Py_VISIT(self->cache_info_type);
1822
31.6k
    Py_VISIT(self->dict);
1823
31.6k
    return 0;
1824
31.6k
}
1825
1826
1827
PyDoc_STRVAR(lru_cache_doc,
1828
"Create a cached callable that wraps another function.\n\
1829
\n\
1830
user_function:      the function being cached\n\
1831
\n\
1832
maxsize:  0         for no caching\n\
1833
          None      for unlimited cache size\n\
1834
          n         for a bounded cache\n\
1835
\n\
1836
typed:    False     cache f(3) and f(3.0) as identical calls\n\
1837
          True      cache f(3) and f(3.0) as distinct calls\n\
1838
\n\
1839
cache_info_type:    namedtuple class with the fields:\n\
1840
                        hits misses currsize maxsize\n"
1841
);
1842
1843
static PyMethodDef lru_cache_methods[] = {
1844
    _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_INFO_METHODDEF
1845
    _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_CLEAR_METHODDEF
1846
    {"__reduce__", lru_cache_reduce, METH_NOARGS},
1847
    {"__copy__", lru_cache_copy, METH_VARARGS},
1848
    {"__deepcopy__", lru_cache_deepcopy, METH_VARARGS},
1849
    {NULL}
1850
};
1851
1852
static PyGetSetDef lru_cache_getsetlist[] = {
1853
    {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1854
    {NULL}
1855
};
1856
1857
static PyMemberDef lru_cache_memberlist[] = {
1858
    {"__dictoffset__", Py_T_PYSSIZET,
1859
     offsetof(lru_cache_object, dict), Py_READONLY},
1860
    {"__weaklistoffset__", Py_T_PYSSIZET,
1861
     offsetof(lru_cache_object, weakreflist), Py_READONLY},
1862
    {NULL}  /* Sentinel */
1863
};
1864
1865
static PyType_Slot lru_cache_type_slots[] = {
1866
    {Py_tp_dealloc, lru_cache_dealloc},
1867
    {Py_tp_call, lru_cache_call},
1868
    {Py_tp_doc, (void *)lru_cache_doc},
1869
    {Py_tp_traverse, lru_cache_tp_traverse},
1870
    {Py_tp_clear, lru_cache_tp_clear},
1871
    {Py_tp_methods, lru_cache_methods},
1872
    {Py_tp_members, lru_cache_memberlist},
1873
    {Py_tp_getset, lru_cache_getsetlist},
1874
    {Py_tp_descr_get, lru_cache_descr_get},
1875
    {Py_tp_new, lru_cache_new},
1876
    {0, 0}
1877
};
1878
1879
static PyType_Spec lru_cache_type_spec = {
1880
    .name = "functools._lru_cache_wrapper",
1881
    .basicsize = sizeof(lru_cache_object),
1882
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1883
             Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_IMMUTABLETYPE,
1884
    .slots = lru_cache_type_slots
1885
};
1886
1887
1888
/* module level code ********************************************************/
1889
1890
PyDoc_STRVAR(_functools_doc,
1891
"Tools that operate on functions.");
1892
1893
static PyMethodDef _functools_methods[] = {
1894
    _FUNCTOOLS_REDUCE_METHODDEF
1895
    _FUNCTOOLS_CMP_TO_KEY_METHODDEF
1896
    {NULL,              NULL}           /* sentinel */
1897
};
1898
1899
static int
1900
_functools_exec(PyObject *module)
1901
11
{
1902
11
    _functools_state *state = get_functools_state(module);
1903
11
    state->kwd_mark = _PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type);
1904
11
    if (state->kwd_mark == NULL) {
1905
0
        return -1;
1906
0
    }
1907
1908
11
    state->placeholder_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1909
11
        &placeholder_type_spec, NULL);
1910
11
    if (state->placeholder_type == NULL) {
1911
0
        return -1;
1912
0
    }
1913
11
    if (PyModule_AddType(module, state->placeholder_type) < 0) {
1914
0
        return -1;
1915
0
    }
1916
1917
11
    PyObject *placeholder = PyObject_CallNoArgs((PyObject *)state->placeholder_type);
1918
11
    if (placeholder == NULL) {
1919
0
        return -1;
1920
0
    }
1921
11
    if (PyModule_AddObjectRef(module, "Placeholder", placeholder) < 0) {
1922
0
        Py_DECREF(placeholder);
1923
0
        return -1;
1924
0
    }
1925
11
    Py_DECREF(placeholder);
1926
1927
11
    state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1928
11
        &partial_type_spec, NULL);
1929
11
    if (state->partial_type == NULL) {
1930
0
        return -1;
1931
0
    }
1932
11
    if (PyModule_AddType(module, state->partial_type) < 0) {
1933
0
        return -1;
1934
0
    }
1935
1936
11
    PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
1937
11
        &lru_cache_type_spec, NULL);
1938
11
    if (lru_cache_type == NULL) {
1939
0
        return -1;
1940
0
    }
1941
11
    if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
1942
0
        Py_DECREF(lru_cache_type);
1943
0
        return -1;
1944
0
    }
1945
11
    Py_DECREF(lru_cache_type);
1946
1947
11
    state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
1948
11
        &keyobject_type_spec, NULL);
1949
11
    if (state->keyobject_type == NULL) {
1950
0
        return -1;
1951
0
    }
1952
    // keyobject_type is used only internally.
1953
    // So we don't expose it in module namespace.
1954
1955
11
    state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
1956
11
        module, &lru_list_elem_type_spec, NULL);
1957
11
    if (state->lru_list_elem_type == NULL) {
1958
0
        return -1;
1959
0
    }
1960
    // lru_list_elem is used only in _lru_cache_wrapper.
1961
    // So we don't expose it in module namespace.
1962
1963
11
    return 0;
1964
11
}
1965
1966
static int
1967
_functools_traverse(PyObject *module, visitproc visit, void *arg)
1968
4.10k
{
1969
4.10k
    _functools_state *state = get_functools_state(module);
1970
4.10k
    Py_VISIT(state->kwd_mark);
1971
4.10k
    Py_VISIT(state->placeholder_type);
1972
4.10k
    Py_VISIT(state->placeholder);
1973
4.10k
    Py_VISIT(state->partial_type);
1974
4.10k
    Py_VISIT(state->keyobject_type);
1975
4.10k
    Py_VISIT(state->lru_list_elem_type);
1976
4.10k
    return 0;
1977
4.10k
}
1978
1979
static int
1980
_functools_clear(PyObject *module)
1981
0
{
1982
0
    _functools_state *state = get_functools_state(module);
1983
0
    Py_CLEAR(state->kwd_mark);
1984
0
    Py_CLEAR(state->placeholder_type);
1985
0
    Py_CLEAR(state->placeholder);
1986
0
    Py_CLEAR(state->partial_type);
1987
0
    Py_CLEAR(state->keyobject_type);
1988
0
    Py_CLEAR(state->lru_list_elem_type);
1989
0
    return 0;
1990
0
}
1991
1992
static void
1993
_functools_free(void *module)
1994
0
{
1995
0
    (void)_functools_clear((PyObject *)module);
1996
0
}
1997
1998
static struct PyModuleDef_Slot _functools_slots[] = {
1999
    {Py_mod_exec, _functools_exec},
2000
    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
2001
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
2002
    {0, NULL}
2003
};
2004
2005
static struct PyModuleDef _functools_module = {
2006
    PyModuleDef_HEAD_INIT,
2007
    .m_name = "_functools",
2008
    .m_doc = _functools_doc,
2009
    .m_size = sizeof(_functools_state),
2010
    .m_methods = _functools_methods,
2011
    .m_slots = _functools_slots,
2012
    .m_traverse = _functools_traverse,
2013
    .m_clear = _functools_clear,
2014
    .m_free = _functools_free,
2015
};
2016
2017
PyMODINIT_FUNC
2018
PyInit__functools(void)
2019
11
{
2020
11
    return PyModuleDef_Init(&_functools_module);
2021
11
}