Coverage Report

Created: 2026-02-26 06:53

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