Coverage Report

Created: 2025-09-05 07:10

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