Coverage Report

Created: 2026-03-08 06:40

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