Coverage Report

Created: 2025-08-29 07:13

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