Coverage Report

Created: 2026-05-30 06:18

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