Coverage Report

Created: 2025-07-04 06:49

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