17db96d56Sopenharmony_ci#include "Python.h"
27db96d56Sopenharmony_ci#include "pycore_call.h"          // _PyObject_CallNoArgs()
37db96d56Sopenharmony_ci#include "pycore_long.h"          // _PyLong_GetZero()
47db96d56Sopenharmony_ci#include "pycore_moduleobject.h"  // _PyModule_GetState()
57db96d56Sopenharmony_ci#include "pycore_object.h"        // _PyObject_GC_TRACK
67db96d56Sopenharmony_ci#include "pycore_pystate.h"       // _PyThreadState_GET()
77db96d56Sopenharmony_ci#include "pycore_tuple.h"         // _PyTuple_ITEMS()
87db96d56Sopenharmony_ci#include "structmember.h"         // PyMemberDef
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci/* _functools module written and maintained
117db96d56Sopenharmony_ci   by Hye-Shik Chang <perky@FreeBSD.org>
127db96d56Sopenharmony_ci   with adaptations by Raymond Hettinger <python@rcn.com>
137db96d56Sopenharmony_ci   Copyright (c) 2004, 2005, 2006 Python Software Foundation.
147db96d56Sopenharmony_ci   All rights reserved.
157db96d56Sopenharmony_ci*/
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_citypedef struct _functools_state {
187db96d56Sopenharmony_ci    /* this object is used delimit args and keywords in the cache keys */
197db96d56Sopenharmony_ci    PyObject *kwd_mark;
207db96d56Sopenharmony_ci    PyTypeObject *partial_type;
217db96d56Sopenharmony_ci    PyTypeObject *keyobject_type;
227db96d56Sopenharmony_ci    PyTypeObject *lru_list_elem_type;
237db96d56Sopenharmony_ci} _functools_state;
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_cistatic inline _functools_state *
267db96d56Sopenharmony_ciget_functools_state(PyObject *module)
277db96d56Sopenharmony_ci{
287db96d56Sopenharmony_ci    void *state = _PyModule_GetState(module);
297db96d56Sopenharmony_ci    assert(state != NULL);
307db96d56Sopenharmony_ci    return (_functools_state *)state;
317db96d56Sopenharmony_ci}
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ci/* partial object **********************************************************/
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_citypedef struct {
377db96d56Sopenharmony_ci    PyObject_HEAD
387db96d56Sopenharmony_ci    PyObject *fn;
397db96d56Sopenharmony_ci    PyObject *args;
407db96d56Sopenharmony_ci    PyObject *kw;
417db96d56Sopenharmony_ci    PyObject *dict;        /* __dict__ */
427db96d56Sopenharmony_ci    PyObject *weakreflist; /* List of weak references */
437db96d56Sopenharmony_ci    vectorcallfunc vectorcall;
447db96d56Sopenharmony_ci} partialobject;
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_cistatic void partial_setvectorcall(partialobject *pto);
477db96d56Sopenharmony_cistatic struct PyModuleDef _functools_module;
487db96d56Sopenharmony_cistatic PyObject *
497db96d56Sopenharmony_cipartial_call(partialobject *pto, PyObject *args, PyObject *kwargs);
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_cistatic inline _functools_state *
527db96d56Sopenharmony_ciget_functools_state_by_type(PyTypeObject *type)
537db96d56Sopenharmony_ci{
547db96d56Sopenharmony_ci    PyObject *module = PyType_GetModuleByDef(type, &_functools_module);
557db96d56Sopenharmony_ci    if (module == NULL) {
567db96d56Sopenharmony_ci        return NULL;
577db96d56Sopenharmony_ci    }
587db96d56Sopenharmony_ci    return get_functools_state(module);
597db96d56Sopenharmony_ci}
607db96d56Sopenharmony_ci
617db96d56Sopenharmony_cistatic PyObject *
627db96d56Sopenharmony_cipartial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
637db96d56Sopenharmony_ci{
647db96d56Sopenharmony_ci    PyObject *func, *pargs, *nargs, *pkw;
657db96d56Sopenharmony_ci    partialobject *pto;
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci    if (PyTuple_GET_SIZE(args) < 1) {
687db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
697db96d56Sopenharmony_ci                        "type 'partial' takes at least one argument");
707db96d56Sopenharmony_ci        return NULL;
717db96d56Sopenharmony_ci    }
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci    pargs = pkw = NULL;
747db96d56Sopenharmony_ci    func = PyTuple_GET_ITEM(args, 0);
757db96d56Sopenharmony_ci    if (Py_TYPE(func)->tp_call == (ternaryfunc)partial_call) {
767db96d56Sopenharmony_ci        // The type of "func" might not be exactly the same type object
777db96d56Sopenharmony_ci        // as "type", but if it is called using partial_call, it must have the
787db96d56Sopenharmony_ci        // same memory layout (fn, args and kw members).
797db96d56Sopenharmony_ci        // We can use its underlying function directly and merge the arguments.
807db96d56Sopenharmony_ci        partialobject *part = (partialobject *)func;
817db96d56Sopenharmony_ci        if (part->dict == NULL) {
827db96d56Sopenharmony_ci            pargs = part->args;
837db96d56Sopenharmony_ci            pkw = part->kw;
847db96d56Sopenharmony_ci            func = part->fn;
857db96d56Sopenharmony_ci            assert(PyTuple_Check(pargs));
867db96d56Sopenharmony_ci            assert(PyDict_Check(pkw));
877db96d56Sopenharmony_ci        }
887db96d56Sopenharmony_ci    }
897db96d56Sopenharmony_ci    if (!PyCallable_Check(func)) {
907db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
917db96d56Sopenharmony_ci                        "the first argument must be callable");
927db96d56Sopenharmony_ci        return NULL;
937db96d56Sopenharmony_ci    }
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci    /* create partialobject structure */
967db96d56Sopenharmony_ci    pto = (partialobject *)type->tp_alloc(type, 0);
977db96d56Sopenharmony_ci    if (pto == NULL)
987db96d56Sopenharmony_ci        return NULL;
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_ci    pto->fn = func;
1017db96d56Sopenharmony_ci    Py_INCREF(func);
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci    nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
1047db96d56Sopenharmony_ci    if (nargs == NULL) {
1057db96d56Sopenharmony_ci        Py_DECREF(pto);
1067db96d56Sopenharmony_ci        return NULL;
1077db96d56Sopenharmony_ci    }
1087db96d56Sopenharmony_ci    if (pargs == NULL) {
1097db96d56Sopenharmony_ci        pto->args = nargs;
1107db96d56Sopenharmony_ci    }
1117db96d56Sopenharmony_ci    else {
1127db96d56Sopenharmony_ci        pto->args = PySequence_Concat(pargs, nargs);
1137db96d56Sopenharmony_ci        Py_DECREF(nargs);
1147db96d56Sopenharmony_ci        if (pto->args == NULL) {
1157db96d56Sopenharmony_ci            Py_DECREF(pto);
1167db96d56Sopenharmony_ci            return NULL;
1177db96d56Sopenharmony_ci        }
1187db96d56Sopenharmony_ci        assert(PyTuple_Check(pto->args));
1197db96d56Sopenharmony_ci    }
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci    if (pkw == NULL || PyDict_GET_SIZE(pkw) == 0) {
1227db96d56Sopenharmony_ci        if (kw == NULL) {
1237db96d56Sopenharmony_ci            pto->kw = PyDict_New();
1247db96d56Sopenharmony_ci        }
1257db96d56Sopenharmony_ci        else if (Py_REFCNT(kw) == 1) {
1267db96d56Sopenharmony_ci            Py_INCREF(kw);
1277db96d56Sopenharmony_ci            pto->kw = kw;
1287db96d56Sopenharmony_ci        }
1297db96d56Sopenharmony_ci        else {
1307db96d56Sopenharmony_ci            pto->kw = PyDict_Copy(kw);
1317db96d56Sopenharmony_ci        }
1327db96d56Sopenharmony_ci    }
1337db96d56Sopenharmony_ci    else {
1347db96d56Sopenharmony_ci        pto->kw = PyDict_Copy(pkw);
1357db96d56Sopenharmony_ci        if (kw != NULL && pto->kw != NULL) {
1367db96d56Sopenharmony_ci            if (PyDict_Merge(pto->kw, kw, 1) != 0) {
1377db96d56Sopenharmony_ci                Py_DECREF(pto);
1387db96d56Sopenharmony_ci                return NULL;
1397db96d56Sopenharmony_ci            }
1407db96d56Sopenharmony_ci        }
1417db96d56Sopenharmony_ci    }
1427db96d56Sopenharmony_ci    if (pto->kw == NULL) {
1437db96d56Sopenharmony_ci        Py_DECREF(pto);
1447db96d56Sopenharmony_ci        return NULL;
1457db96d56Sopenharmony_ci    }
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ci    partial_setvectorcall(pto);
1487db96d56Sopenharmony_ci    return (PyObject *)pto;
1497db96d56Sopenharmony_ci}
1507db96d56Sopenharmony_ci
1517db96d56Sopenharmony_cistatic int
1527db96d56Sopenharmony_cipartial_clear(partialobject *pto)
1537db96d56Sopenharmony_ci{
1547db96d56Sopenharmony_ci    Py_CLEAR(pto->fn);
1557db96d56Sopenharmony_ci    Py_CLEAR(pto->args);
1567db96d56Sopenharmony_ci    Py_CLEAR(pto->kw);
1577db96d56Sopenharmony_ci    Py_CLEAR(pto->dict);
1587db96d56Sopenharmony_ci    return 0;
1597db96d56Sopenharmony_ci}
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_cistatic int
1627db96d56Sopenharmony_cipartial_traverse(partialobject *pto, visitproc visit, void *arg)
1637db96d56Sopenharmony_ci{
1647db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(pto));
1657db96d56Sopenharmony_ci    Py_VISIT(pto->fn);
1667db96d56Sopenharmony_ci    Py_VISIT(pto->args);
1677db96d56Sopenharmony_ci    Py_VISIT(pto->kw);
1687db96d56Sopenharmony_ci    Py_VISIT(pto->dict);
1697db96d56Sopenharmony_ci    return 0;
1707db96d56Sopenharmony_ci}
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_cistatic void
1737db96d56Sopenharmony_cipartial_dealloc(partialobject *pto)
1747db96d56Sopenharmony_ci{
1757db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(pto);
1767db96d56Sopenharmony_ci    /* bpo-31095: UnTrack is needed before calling any callbacks */
1777db96d56Sopenharmony_ci    PyObject_GC_UnTrack(pto);
1787db96d56Sopenharmony_ci    if (pto->weakreflist != NULL) {
1797db96d56Sopenharmony_ci        PyObject_ClearWeakRefs((PyObject *) pto);
1807db96d56Sopenharmony_ci    }
1817db96d56Sopenharmony_ci    (void)partial_clear(pto);
1827db96d56Sopenharmony_ci    tp->tp_free(pto);
1837db96d56Sopenharmony_ci    Py_DECREF(tp);
1847db96d56Sopenharmony_ci}
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci
1877db96d56Sopenharmony_ci/* Merging keyword arguments using the vectorcall convention is messy, so
1887db96d56Sopenharmony_ci * if we would need to do that, we stop using vectorcall and fall back
1897db96d56Sopenharmony_ci * to using partial_call() instead. */
1907db96d56Sopenharmony_ciPy_NO_INLINE static PyObject *
1917db96d56Sopenharmony_cipartial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto,
1927db96d56Sopenharmony_ci                            PyObject *const *args, size_t nargsf,
1937db96d56Sopenharmony_ci                            PyObject *kwnames)
1947db96d56Sopenharmony_ci{
1957db96d56Sopenharmony_ci    pto->vectorcall = NULL;
1967db96d56Sopenharmony_ci    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
1977db96d56Sopenharmony_ci    return _PyObject_MakeTpCall(tstate, (PyObject *)pto,
1987db96d56Sopenharmony_ci                                args, nargs, kwnames);
1997db96d56Sopenharmony_ci}
2007db96d56Sopenharmony_ci
2017db96d56Sopenharmony_cistatic PyObject *
2027db96d56Sopenharmony_cipartial_vectorcall(partialobject *pto, PyObject *const *args,
2037db96d56Sopenharmony_ci                   size_t nargsf, PyObject *kwnames)
2047db96d56Sopenharmony_ci{
2057db96d56Sopenharmony_ci    PyThreadState *tstate = _PyThreadState_GET();
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ci    /* pto->kw is mutable, so need to check every time */
2087db96d56Sopenharmony_ci    if (PyDict_GET_SIZE(pto->kw)) {
2097db96d56Sopenharmony_ci        return partial_vectorcall_fallback(tstate, pto, args, nargsf, kwnames);
2107db96d56Sopenharmony_ci    }
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_ci    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
2137db96d56Sopenharmony_ci    Py_ssize_t nargs_total = nargs;
2147db96d56Sopenharmony_ci    if (kwnames != NULL) {
2157db96d56Sopenharmony_ci        nargs_total += PyTuple_GET_SIZE(kwnames);
2167db96d56Sopenharmony_ci    }
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci    PyObject **pto_args = _PyTuple_ITEMS(pto->args);
2197db96d56Sopenharmony_ci    Py_ssize_t pto_nargs = PyTuple_GET_SIZE(pto->args);
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ci    /* Fast path if we're called without arguments */
2227db96d56Sopenharmony_ci    if (nargs_total == 0) {
2237db96d56Sopenharmony_ci        return _PyObject_VectorcallTstate(tstate, pto->fn,
2247db96d56Sopenharmony_ci                                          pto_args, pto_nargs, NULL);
2257db96d56Sopenharmony_ci    }
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci    /* Fast path using PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
2287db96d56Sopenharmony_ci     * positional argument */
2297db96d56Sopenharmony_ci    if (pto_nargs == 1 && (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET)) {
2307db96d56Sopenharmony_ci        PyObject **newargs = (PyObject **)args - 1;
2317db96d56Sopenharmony_ci        PyObject *tmp = newargs[0];
2327db96d56Sopenharmony_ci        newargs[0] = pto_args[0];
2337db96d56Sopenharmony_ci        PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn,
2347db96d56Sopenharmony_ci                                                   newargs, nargs + 1, kwnames);
2357db96d56Sopenharmony_ci        newargs[0] = tmp;
2367db96d56Sopenharmony_ci        return ret;
2377db96d56Sopenharmony_ci    }
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ci    Py_ssize_t newnargs_total = pto_nargs + nargs_total;
2407db96d56Sopenharmony_ci
2417db96d56Sopenharmony_ci    PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
2427db96d56Sopenharmony_ci    PyObject *ret;
2437db96d56Sopenharmony_ci    PyObject **stack;
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci    if (newnargs_total <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
2467db96d56Sopenharmony_ci        stack = small_stack;
2477db96d56Sopenharmony_ci    }
2487db96d56Sopenharmony_ci    else {
2497db96d56Sopenharmony_ci        stack = PyMem_Malloc(newnargs_total * sizeof(PyObject *));
2507db96d56Sopenharmony_ci        if (stack == NULL) {
2517db96d56Sopenharmony_ci            PyErr_NoMemory();
2527db96d56Sopenharmony_ci            return NULL;
2537db96d56Sopenharmony_ci        }
2547db96d56Sopenharmony_ci    }
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci    /* Copy to new stack, using borrowed references */
2577db96d56Sopenharmony_ci    memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
2587db96d56Sopenharmony_ci    memcpy(stack + pto_nargs, args, nargs_total * sizeof(PyObject*));
2597db96d56Sopenharmony_ci
2607db96d56Sopenharmony_ci    ret = _PyObject_VectorcallTstate(tstate, pto->fn,
2617db96d56Sopenharmony_ci                                     stack, pto_nargs + nargs, kwnames);
2627db96d56Sopenharmony_ci    if (stack != small_stack) {
2637db96d56Sopenharmony_ci        PyMem_Free(stack);
2647db96d56Sopenharmony_ci    }
2657db96d56Sopenharmony_ci    return ret;
2667db96d56Sopenharmony_ci}
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_ci/* Set pto->vectorcall depending on the parameters of the partial object */
2697db96d56Sopenharmony_cistatic void
2707db96d56Sopenharmony_cipartial_setvectorcall(partialobject *pto)
2717db96d56Sopenharmony_ci{
2727db96d56Sopenharmony_ci    if (_PyVectorcall_Function(pto->fn) == NULL) {
2737db96d56Sopenharmony_ci        /* Don't use vectorcall if the underlying function doesn't support it */
2747db96d56Sopenharmony_ci        pto->vectorcall = NULL;
2757db96d56Sopenharmony_ci    }
2767db96d56Sopenharmony_ci    /* We could have a special case if there are no arguments,
2777db96d56Sopenharmony_ci     * but that is unlikely (why use partial without arguments?),
2787db96d56Sopenharmony_ci     * so we don't optimize that */
2797db96d56Sopenharmony_ci    else {
2807db96d56Sopenharmony_ci        pto->vectorcall = (vectorcallfunc)partial_vectorcall;
2817db96d56Sopenharmony_ci    }
2827db96d56Sopenharmony_ci}
2837db96d56Sopenharmony_ci
2847db96d56Sopenharmony_ci
2857db96d56Sopenharmony_cistatic PyObject *
2867db96d56Sopenharmony_cipartial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
2877db96d56Sopenharmony_ci{
2887db96d56Sopenharmony_ci    assert(PyCallable_Check(pto->fn));
2897db96d56Sopenharmony_ci    assert(PyTuple_Check(pto->args));
2907db96d56Sopenharmony_ci    assert(PyDict_Check(pto->kw));
2917db96d56Sopenharmony_ci
2927db96d56Sopenharmony_ci    /* Merge keywords */
2937db96d56Sopenharmony_ci    PyObject *kwargs2;
2947db96d56Sopenharmony_ci    if (PyDict_GET_SIZE(pto->kw) == 0) {
2957db96d56Sopenharmony_ci        /* kwargs can be NULL */
2967db96d56Sopenharmony_ci        kwargs2 = kwargs;
2977db96d56Sopenharmony_ci        Py_XINCREF(kwargs2);
2987db96d56Sopenharmony_ci    }
2997db96d56Sopenharmony_ci    else {
3007db96d56Sopenharmony_ci        /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
3017db96d56Sopenharmony_ci           copied, because a function using "**kwargs" can modify the
3027db96d56Sopenharmony_ci           dictionary. */
3037db96d56Sopenharmony_ci        kwargs2 = PyDict_Copy(pto->kw);
3047db96d56Sopenharmony_ci        if (kwargs2 == NULL) {
3057db96d56Sopenharmony_ci            return NULL;
3067db96d56Sopenharmony_ci        }
3077db96d56Sopenharmony_ci
3087db96d56Sopenharmony_ci        if (kwargs != NULL) {
3097db96d56Sopenharmony_ci            if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
3107db96d56Sopenharmony_ci                Py_DECREF(kwargs2);
3117db96d56Sopenharmony_ci                return NULL;
3127db96d56Sopenharmony_ci            }
3137db96d56Sopenharmony_ci        }
3147db96d56Sopenharmony_ci    }
3157db96d56Sopenharmony_ci
3167db96d56Sopenharmony_ci    /* Merge positional arguments */
3177db96d56Sopenharmony_ci    /* Note: tupleconcat() is optimized for empty tuples */
3187db96d56Sopenharmony_ci    PyObject *args2 = PySequence_Concat(pto->args, args);
3197db96d56Sopenharmony_ci    if (args2 == NULL) {
3207db96d56Sopenharmony_ci        Py_XDECREF(kwargs2);
3217db96d56Sopenharmony_ci        return NULL;
3227db96d56Sopenharmony_ci    }
3237db96d56Sopenharmony_ci
3247db96d56Sopenharmony_ci    PyObject *res = PyObject_Call(pto->fn, args2, kwargs2);
3257db96d56Sopenharmony_ci    Py_DECREF(args2);
3267db96d56Sopenharmony_ci    Py_XDECREF(kwargs2);
3277db96d56Sopenharmony_ci    return res;
3287db96d56Sopenharmony_ci}
3297db96d56Sopenharmony_ci
3307db96d56Sopenharmony_ciPyDoc_STRVAR(partial_doc,
3317db96d56Sopenharmony_ci"partial(func, *args, **keywords) - new function with partial application\n\
3327db96d56Sopenharmony_ci    of the given arguments and keywords.\n");
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci#define OFF(x) offsetof(partialobject, x)
3357db96d56Sopenharmony_cistatic PyMemberDef partial_memberlist[] = {
3367db96d56Sopenharmony_ci    {"func",            T_OBJECT,       OFF(fn),        READONLY,
3377db96d56Sopenharmony_ci     "function object to use in future partial calls"},
3387db96d56Sopenharmony_ci    {"args",            T_OBJECT,       OFF(args),      READONLY,
3397db96d56Sopenharmony_ci     "tuple of arguments to future partial calls"},
3407db96d56Sopenharmony_ci    {"keywords",        T_OBJECT,       OFF(kw),        READONLY,
3417db96d56Sopenharmony_ci     "dictionary of keyword arguments to future partial calls"},
3427db96d56Sopenharmony_ci    {"__weaklistoffset__", T_PYSSIZET,
3437db96d56Sopenharmony_ci     offsetof(partialobject, weakreflist), READONLY},
3447db96d56Sopenharmony_ci    {"__dictoffset__", T_PYSSIZET,
3457db96d56Sopenharmony_ci     offsetof(partialobject, dict), READONLY},
3467db96d56Sopenharmony_ci    {"__vectorcalloffset__", T_PYSSIZET,
3477db96d56Sopenharmony_ci     offsetof(partialobject, vectorcall), READONLY},
3487db96d56Sopenharmony_ci    {NULL}  /* Sentinel */
3497db96d56Sopenharmony_ci};
3507db96d56Sopenharmony_ci
3517db96d56Sopenharmony_cistatic PyGetSetDef partial_getsetlist[] = {
3527db96d56Sopenharmony_ci    {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
3537db96d56Sopenharmony_ci    {NULL} /* Sentinel */
3547db96d56Sopenharmony_ci};
3557db96d56Sopenharmony_ci
3567db96d56Sopenharmony_cistatic PyObject *
3577db96d56Sopenharmony_cipartial_repr(partialobject *pto)
3587db96d56Sopenharmony_ci{
3597db96d56Sopenharmony_ci    PyObject *result = NULL;
3607db96d56Sopenharmony_ci    PyObject *arglist;
3617db96d56Sopenharmony_ci    Py_ssize_t i, n;
3627db96d56Sopenharmony_ci    PyObject *key, *value;
3637db96d56Sopenharmony_ci    int status;
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_ci    status = Py_ReprEnter((PyObject *)pto);
3667db96d56Sopenharmony_ci    if (status != 0) {
3677db96d56Sopenharmony_ci        if (status < 0)
3687db96d56Sopenharmony_ci            return NULL;
3697db96d56Sopenharmony_ci        return PyUnicode_FromString("...");
3707db96d56Sopenharmony_ci    }
3717db96d56Sopenharmony_ci
3727db96d56Sopenharmony_ci    arglist = PyUnicode_FromString("");
3737db96d56Sopenharmony_ci    if (arglist == NULL)
3747db96d56Sopenharmony_ci        goto done;
3757db96d56Sopenharmony_ci    /* Pack positional arguments */
3767db96d56Sopenharmony_ci    assert (PyTuple_Check(pto->args));
3777db96d56Sopenharmony_ci    n = PyTuple_GET_SIZE(pto->args);
3787db96d56Sopenharmony_ci    for (i = 0; i < n; i++) {
3797db96d56Sopenharmony_ci        Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
3807db96d56Sopenharmony_ci                                        PyTuple_GET_ITEM(pto->args, i)));
3817db96d56Sopenharmony_ci        if (arglist == NULL)
3827db96d56Sopenharmony_ci            goto done;
3837db96d56Sopenharmony_ci    }
3847db96d56Sopenharmony_ci    /* Pack keyword arguments */
3857db96d56Sopenharmony_ci    assert (PyDict_Check(pto->kw));
3867db96d56Sopenharmony_ci    for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
3877db96d56Sopenharmony_ci        /* Prevent key.__str__ from deleting the value. */
3887db96d56Sopenharmony_ci        Py_INCREF(value);
3897db96d56Sopenharmony_ci        Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
3907db96d56Sopenharmony_ci                                                key, value));
3917db96d56Sopenharmony_ci        Py_DECREF(value);
3927db96d56Sopenharmony_ci        if (arglist == NULL)
3937db96d56Sopenharmony_ci            goto done;
3947db96d56Sopenharmony_ci    }
3957db96d56Sopenharmony_ci    result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
3967db96d56Sopenharmony_ci                                  pto->fn, arglist);
3977db96d56Sopenharmony_ci    Py_DECREF(arglist);
3987db96d56Sopenharmony_ci
3997db96d56Sopenharmony_ci done:
4007db96d56Sopenharmony_ci    Py_ReprLeave((PyObject *)pto);
4017db96d56Sopenharmony_ci    return result;
4027db96d56Sopenharmony_ci}
4037db96d56Sopenharmony_ci
4047db96d56Sopenharmony_ci/* Pickle strategy:
4057db96d56Sopenharmony_ci   __reduce__ by itself doesn't support getting kwargs in the unpickle
4067db96d56Sopenharmony_ci   operation so we define a __setstate__ that replaces all the information
4077db96d56Sopenharmony_ci   about the partial.  If we only replaced part of it someone would use
4087db96d56Sopenharmony_ci   it as a hook to do strange things.
4097db96d56Sopenharmony_ci */
4107db96d56Sopenharmony_ci
4117db96d56Sopenharmony_cistatic PyObject *
4127db96d56Sopenharmony_cipartial_reduce(partialobject *pto, PyObject *unused)
4137db96d56Sopenharmony_ci{
4147db96d56Sopenharmony_ci    return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
4157db96d56Sopenharmony_ci                         pto->args, pto->kw,
4167db96d56Sopenharmony_ci                         pto->dict ? pto->dict : Py_None);
4177db96d56Sopenharmony_ci}
4187db96d56Sopenharmony_ci
4197db96d56Sopenharmony_cistatic PyObject *
4207db96d56Sopenharmony_cipartial_setstate(partialobject *pto, PyObject *state)
4217db96d56Sopenharmony_ci{
4227db96d56Sopenharmony_ci    PyObject *fn, *fnargs, *kw, *dict;
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_ci    if (!PyTuple_Check(state) ||
4257db96d56Sopenharmony_ci        !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
4267db96d56Sopenharmony_ci        !PyCallable_Check(fn) ||
4277db96d56Sopenharmony_ci        !PyTuple_Check(fnargs) ||
4287db96d56Sopenharmony_ci        (kw != Py_None && !PyDict_Check(kw)))
4297db96d56Sopenharmony_ci    {
4307db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "invalid partial state");
4317db96d56Sopenharmony_ci        return NULL;
4327db96d56Sopenharmony_ci    }
4337db96d56Sopenharmony_ci
4347db96d56Sopenharmony_ci    if(!PyTuple_CheckExact(fnargs))
4357db96d56Sopenharmony_ci        fnargs = PySequence_Tuple(fnargs);
4367db96d56Sopenharmony_ci    else
4377db96d56Sopenharmony_ci        Py_INCREF(fnargs);
4387db96d56Sopenharmony_ci    if (fnargs == NULL)
4397db96d56Sopenharmony_ci        return NULL;
4407db96d56Sopenharmony_ci
4417db96d56Sopenharmony_ci    if (kw == Py_None)
4427db96d56Sopenharmony_ci        kw = PyDict_New();
4437db96d56Sopenharmony_ci    else if(!PyDict_CheckExact(kw))
4447db96d56Sopenharmony_ci        kw = PyDict_Copy(kw);
4457db96d56Sopenharmony_ci    else
4467db96d56Sopenharmony_ci        Py_INCREF(kw);
4477db96d56Sopenharmony_ci    if (kw == NULL) {
4487db96d56Sopenharmony_ci        Py_DECREF(fnargs);
4497db96d56Sopenharmony_ci        return NULL;
4507db96d56Sopenharmony_ci    }
4517db96d56Sopenharmony_ci
4527db96d56Sopenharmony_ci    if (dict == Py_None)
4537db96d56Sopenharmony_ci        dict = NULL;
4547db96d56Sopenharmony_ci    else
4557db96d56Sopenharmony_ci        Py_INCREF(dict);
4567db96d56Sopenharmony_ci
4577db96d56Sopenharmony_ci    Py_INCREF(fn);
4587db96d56Sopenharmony_ci    Py_SETREF(pto->fn, fn);
4597db96d56Sopenharmony_ci    Py_SETREF(pto->args, fnargs);
4607db96d56Sopenharmony_ci    Py_SETREF(pto->kw, kw);
4617db96d56Sopenharmony_ci    Py_XSETREF(pto->dict, dict);
4627db96d56Sopenharmony_ci    partial_setvectorcall(pto);
4637db96d56Sopenharmony_ci    Py_RETURN_NONE;
4647db96d56Sopenharmony_ci}
4657db96d56Sopenharmony_ci
4667db96d56Sopenharmony_cistatic PyMethodDef partial_methods[] = {
4677db96d56Sopenharmony_ci    {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
4687db96d56Sopenharmony_ci    {"__setstate__", (PyCFunction)partial_setstate, METH_O},
4697db96d56Sopenharmony_ci    {"__class_getitem__",    Py_GenericAlias,
4707db96d56Sopenharmony_ci    METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")},
4717db96d56Sopenharmony_ci    {NULL,              NULL}           /* sentinel */
4727db96d56Sopenharmony_ci};
4737db96d56Sopenharmony_ci
4747db96d56Sopenharmony_cistatic PyType_Slot partial_type_slots[] = {
4757db96d56Sopenharmony_ci    {Py_tp_dealloc, partial_dealloc},
4767db96d56Sopenharmony_ci    {Py_tp_repr, partial_repr},
4777db96d56Sopenharmony_ci    {Py_tp_call, partial_call},
4787db96d56Sopenharmony_ci    {Py_tp_getattro, PyObject_GenericGetAttr},
4797db96d56Sopenharmony_ci    {Py_tp_setattro, PyObject_GenericSetAttr},
4807db96d56Sopenharmony_ci    {Py_tp_doc, (void *)partial_doc},
4817db96d56Sopenharmony_ci    {Py_tp_traverse, partial_traverse},
4827db96d56Sopenharmony_ci    {Py_tp_clear, partial_clear},
4837db96d56Sopenharmony_ci    {Py_tp_methods, partial_methods},
4847db96d56Sopenharmony_ci    {Py_tp_members, partial_memberlist},
4857db96d56Sopenharmony_ci    {Py_tp_getset, partial_getsetlist},
4867db96d56Sopenharmony_ci    {Py_tp_new, partial_new},
4877db96d56Sopenharmony_ci    {Py_tp_free, PyObject_GC_Del},
4887db96d56Sopenharmony_ci    {0, 0}
4897db96d56Sopenharmony_ci};
4907db96d56Sopenharmony_ci
4917db96d56Sopenharmony_cistatic PyType_Spec partial_type_spec = {
4927db96d56Sopenharmony_ci    .name = "functools.partial",
4937db96d56Sopenharmony_ci    .basicsize = sizeof(partialobject),
4947db96d56Sopenharmony_ci    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
4957db96d56Sopenharmony_ci             Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL |
4967db96d56Sopenharmony_ci             Py_TPFLAGS_IMMUTABLETYPE,
4977db96d56Sopenharmony_ci    .slots = partial_type_slots
4987db96d56Sopenharmony_ci};
4997db96d56Sopenharmony_ci
5007db96d56Sopenharmony_ci
5017db96d56Sopenharmony_ci/* cmp_to_key ***************************************************************/
5027db96d56Sopenharmony_ci
5037db96d56Sopenharmony_citypedef struct {
5047db96d56Sopenharmony_ci    PyObject_HEAD
5057db96d56Sopenharmony_ci    PyObject *cmp;
5067db96d56Sopenharmony_ci    PyObject *object;
5077db96d56Sopenharmony_ci} keyobject;
5087db96d56Sopenharmony_ci
5097db96d56Sopenharmony_cistatic int
5107db96d56Sopenharmony_cikeyobject_clear(keyobject *ko)
5117db96d56Sopenharmony_ci{
5127db96d56Sopenharmony_ci    Py_CLEAR(ko->cmp);
5137db96d56Sopenharmony_ci    Py_CLEAR(ko->object);
5147db96d56Sopenharmony_ci    return 0;
5157db96d56Sopenharmony_ci}
5167db96d56Sopenharmony_ci
5177db96d56Sopenharmony_cistatic void
5187db96d56Sopenharmony_cikeyobject_dealloc(keyobject *ko)
5197db96d56Sopenharmony_ci{
5207db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(ko);
5217db96d56Sopenharmony_ci    PyObject_GC_UnTrack(ko);
5227db96d56Sopenharmony_ci    (void)keyobject_clear(ko);
5237db96d56Sopenharmony_ci    tp->tp_free(ko);
5247db96d56Sopenharmony_ci    Py_DECREF(tp);
5257db96d56Sopenharmony_ci}
5267db96d56Sopenharmony_ci
5277db96d56Sopenharmony_cistatic int
5287db96d56Sopenharmony_cikeyobject_traverse(keyobject *ko, visitproc visit, void *arg)
5297db96d56Sopenharmony_ci{
5307db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(ko));
5317db96d56Sopenharmony_ci    Py_VISIT(ko->cmp);
5327db96d56Sopenharmony_ci    Py_VISIT(ko->object);
5337db96d56Sopenharmony_ci    return 0;
5347db96d56Sopenharmony_ci}
5357db96d56Sopenharmony_ci
5367db96d56Sopenharmony_cistatic PyMemberDef keyobject_members[] = {
5377db96d56Sopenharmony_ci    {"obj", T_OBJECT,
5387db96d56Sopenharmony_ci     offsetof(keyobject, object), 0,
5397db96d56Sopenharmony_ci     PyDoc_STR("Value wrapped by a key function.")},
5407db96d56Sopenharmony_ci    {NULL}
5417db96d56Sopenharmony_ci};
5427db96d56Sopenharmony_ci
5437db96d56Sopenharmony_cistatic PyObject *
5447db96d56Sopenharmony_cikeyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
5457db96d56Sopenharmony_ci
5467db96d56Sopenharmony_cistatic PyObject *
5477db96d56Sopenharmony_cikeyobject_richcompare(PyObject *ko, PyObject *other, int op);
5487db96d56Sopenharmony_ci
5497db96d56Sopenharmony_cistatic PyType_Slot keyobject_type_slots[] = {
5507db96d56Sopenharmony_ci    {Py_tp_dealloc, keyobject_dealloc},
5517db96d56Sopenharmony_ci    {Py_tp_call, keyobject_call},
5527db96d56Sopenharmony_ci    {Py_tp_getattro, PyObject_GenericGetAttr},
5537db96d56Sopenharmony_ci    {Py_tp_traverse, keyobject_traverse},
5547db96d56Sopenharmony_ci    {Py_tp_clear, keyobject_clear},
5557db96d56Sopenharmony_ci    {Py_tp_richcompare, keyobject_richcompare},
5567db96d56Sopenharmony_ci    {Py_tp_members, keyobject_members},
5577db96d56Sopenharmony_ci    {0, 0}
5587db96d56Sopenharmony_ci};
5597db96d56Sopenharmony_ci
5607db96d56Sopenharmony_cistatic PyType_Spec keyobject_type_spec = {
5617db96d56Sopenharmony_ci    .name = "functools.KeyWrapper",
5627db96d56Sopenharmony_ci    .basicsize = sizeof(keyobject),
5637db96d56Sopenharmony_ci    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
5647db96d56Sopenharmony_ci              Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
5657db96d56Sopenharmony_ci    .slots = keyobject_type_slots
5667db96d56Sopenharmony_ci};
5677db96d56Sopenharmony_ci
5687db96d56Sopenharmony_cistatic PyObject *
5697db96d56Sopenharmony_cikeyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
5707db96d56Sopenharmony_ci{
5717db96d56Sopenharmony_ci    PyObject *object;
5727db96d56Sopenharmony_ci    keyobject *result;
5737db96d56Sopenharmony_ci    static char *kwargs[] = {"obj", NULL};
5747db96d56Sopenharmony_ci
5757db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
5767db96d56Sopenharmony_ci        return NULL;
5777db96d56Sopenharmony_ci
5787db96d56Sopenharmony_ci    result = PyObject_GC_New(keyobject, Py_TYPE(ko));
5797db96d56Sopenharmony_ci    if (result == NULL) {
5807db96d56Sopenharmony_ci        return NULL;
5817db96d56Sopenharmony_ci    }
5827db96d56Sopenharmony_ci    Py_INCREF(ko->cmp);
5837db96d56Sopenharmony_ci    result->cmp = ko->cmp;
5847db96d56Sopenharmony_ci    Py_INCREF(object);
5857db96d56Sopenharmony_ci    result->object = object;
5867db96d56Sopenharmony_ci    PyObject_GC_Track(result);
5877db96d56Sopenharmony_ci    return (PyObject *)result;
5887db96d56Sopenharmony_ci}
5897db96d56Sopenharmony_ci
5907db96d56Sopenharmony_cistatic PyObject *
5917db96d56Sopenharmony_cikeyobject_richcompare(PyObject *ko, PyObject *other, int op)
5927db96d56Sopenharmony_ci{
5937db96d56Sopenharmony_ci    PyObject *res;
5947db96d56Sopenharmony_ci    PyObject *x;
5957db96d56Sopenharmony_ci    PyObject *y;
5967db96d56Sopenharmony_ci    PyObject *compare;
5977db96d56Sopenharmony_ci    PyObject *answer;
5987db96d56Sopenharmony_ci    PyObject* stack[2];
5997db96d56Sopenharmony_ci
6007db96d56Sopenharmony_ci    if (!Py_IS_TYPE(other, Py_TYPE(ko))) {
6017db96d56Sopenharmony_ci        PyErr_Format(PyExc_TypeError, "other argument must be K instance");
6027db96d56Sopenharmony_ci        return NULL;
6037db96d56Sopenharmony_ci    }
6047db96d56Sopenharmony_ci    compare = ((keyobject *) ko)->cmp;
6057db96d56Sopenharmony_ci    assert(compare != NULL);
6067db96d56Sopenharmony_ci    x = ((keyobject *) ko)->object;
6077db96d56Sopenharmony_ci    y = ((keyobject *) other)->object;
6087db96d56Sopenharmony_ci    if (!x || !y){
6097db96d56Sopenharmony_ci        PyErr_Format(PyExc_AttributeError, "object");
6107db96d56Sopenharmony_ci        return NULL;
6117db96d56Sopenharmony_ci    }
6127db96d56Sopenharmony_ci
6137db96d56Sopenharmony_ci    /* Call the user's comparison function and translate the 3-way
6147db96d56Sopenharmony_ci     * result into true or false (or error).
6157db96d56Sopenharmony_ci     */
6167db96d56Sopenharmony_ci    stack[0] = x;
6177db96d56Sopenharmony_ci    stack[1] = y;
6187db96d56Sopenharmony_ci    res = _PyObject_FastCall(compare, stack, 2);
6197db96d56Sopenharmony_ci    if (res == NULL) {
6207db96d56Sopenharmony_ci        return NULL;
6217db96d56Sopenharmony_ci    }
6227db96d56Sopenharmony_ci
6237db96d56Sopenharmony_ci    answer = PyObject_RichCompare(res, _PyLong_GetZero(), op);
6247db96d56Sopenharmony_ci    Py_DECREF(res);
6257db96d56Sopenharmony_ci    return answer;
6267db96d56Sopenharmony_ci}
6277db96d56Sopenharmony_ci
6287db96d56Sopenharmony_cistatic PyObject *
6297db96d56Sopenharmony_cifunctools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
6307db96d56Sopenharmony_ci{
6317db96d56Sopenharmony_ci    PyObject *cmp;
6327db96d56Sopenharmony_ci    static char *kwargs[] = {"mycmp", NULL};
6337db96d56Sopenharmony_ci    keyobject *object;
6347db96d56Sopenharmony_ci    _functools_state *state;
6357db96d56Sopenharmony_ci
6367db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
6377db96d56Sopenharmony_ci        return NULL;
6387db96d56Sopenharmony_ci
6397db96d56Sopenharmony_ci    state = get_functools_state(self);
6407db96d56Sopenharmony_ci    object = PyObject_GC_New(keyobject, state->keyobject_type);
6417db96d56Sopenharmony_ci    if (!object)
6427db96d56Sopenharmony_ci        return NULL;
6437db96d56Sopenharmony_ci    Py_INCREF(cmp);
6447db96d56Sopenharmony_ci    object->cmp = cmp;
6457db96d56Sopenharmony_ci    object->object = NULL;
6467db96d56Sopenharmony_ci    PyObject_GC_Track(object);
6477db96d56Sopenharmony_ci    return (PyObject *)object;
6487db96d56Sopenharmony_ci}
6497db96d56Sopenharmony_ci
6507db96d56Sopenharmony_ciPyDoc_STRVAR(functools_cmp_to_key_doc,
6517db96d56Sopenharmony_ci"Convert a cmp= function into a key= function.");
6527db96d56Sopenharmony_ci
6537db96d56Sopenharmony_ci/* reduce (used to be a builtin) ********************************************/
6547db96d56Sopenharmony_ci
6557db96d56Sopenharmony_cistatic PyObject *
6567db96d56Sopenharmony_cifunctools_reduce(PyObject *self, PyObject *args)
6577db96d56Sopenharmony_ci{
6587db96d56Sopenharmony_ci    PyObject *seq, *func, *result = NULL, *it;
6597db96d56Sopenharmony_ci
6607db96d56Sopenharmony_ci    if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
6617db96d56Sopenharmony_ci        return NULL;
6627db96d56Sopenharmony_ci    if (result != NULL)
6637db96d56Sopenharmony_ci        Py_INCREF(result);
6647db96d56Sopenharmony_ci
6657db96d56Sopenharmony_ci    it = PyObject_GetIter(seq);
6667db96d56Sopenharmony_ci    if (it == NULL) {
6677db96d56Sopenharmony_ci        if (PyErr_ExceptionMatches(PyExc_TypeError))
6687db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError,
6697db96d56Sopenharmony_ci                            "reduce() arg 2 must support iteration");
6707db96d56Sopenharmony_ci        Py_XDECREF(result);
6717db96d56Sopenharmony_ci        return NULL;
6727db96d56Sopenharmony_ci    }
6737db96d56Sopenharmony_ci
6747db96d56Sopenharmony_ci    if ((args = PyTuple_New(2)) == NULL)
6757db96d56Sopenharmony_ci        goto Fail;
6767db96d56Sopenharmony_ci
6777db96d56Sopenharmony_ci    for (;;) {
6787db96d56Sopenharmony_ci        PyObject *op2;
6797db96d56Sopenharmony_ci
6807db96d56Sopenharmony_ci        if (Py_REFCNT(args) > 1) {
6817db96d56Sopenharmony_ci            Py_DECREF(args);
6827db96d56Sopenharmony_ci            if ((args = PyTuple_New(2)) == NULL)
6837db96d56Sopenharmony_ci                goto Fail;
6847db96d56Sopenharmony_ci        }
6857db96d56Sopenharmony_ci
6867db96d56Sopenharmony_ci        op2 = PyIter_Next(it);
6877db96d56Sopenharmony_ci        if (op2 == NULL) {
6887db96d56Sopenharmony_ci            if (PyErr_Occurred())
6897db96d56Sopenharmony_ci                goto Fail;
6907db96d56Sopenharmony_ci            break;
6917db96d56Sopenharmony_ci        }
6927db96d56Sopenharmony_ci
6937db96d56Sopenharmony_ci        if (result == NULL)
6947db96d56Sopenharmony_ci            result = op2;
6957db96d56Sopenharmony_ci        else {
6967db96d56Sopenharmony_ci            /* Update the args tuple in-place */
6977db96d56Sopenharmony_ci            assert(Py_REFCNT(args) == 1);
6987db96d56Sopenharmony_ci            Py_XSETREF(_PyTuple_ITEMS(args)[0], result);
6997db96d56Sopenharmony_ci            Py_XSETREF(_PyTuple_ITEMS(args)[1], op2);
7007db96d56Sopenharmony_ci            if ((result = PyObject_Call(func, args, NULL)) == NULL) {
7017db96d56Sopenharmony_ci                goto Fail;
7027db96d56Sopenharmony_ci            }
7037db96d56Sopenharmony_ci            // bpo-42536: The GC may have untracked this args tuple. Since we're
7047db96d56Sopenharmony_ci            // recycling it, make sure it's tracked again:
7057db96d56Sopenharmony_ci            if (!_PyObject_GC_IS_TRACKED(args)) {
7067db96d56Sopenharmony_ci                _PyObject_GC_TRACK(args);
7077db96d56Sopenharmony_ci            }
7087db96d56Sopenharmony_ci        }
7097db96d56Sopenharmony_ci    }
7107db96d56Sopenharmony_ci
7117db96d56Sopenharmony_ci    Py_DECREF(args);
7127db96d56Sopenharmony_ci
7137db96d56Sopenharmony_ci    if (result == NULL)
7147db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
7157db96d56Sopenharmony_ci                   "reduce() of empty iterable with no initial value");
7167db96d56Sopenharmony_ci
7177db96d56Sopenharmony_ci    Py_DECREF(it);
7187db96d56Sopenharmony_ci    return result;
7197db96d56Sopenharmony_ci
7207db96d56Sopenharmony_ciFail:
7217db96d56Sopenharmony_ci    Py_XDECREF(args);
7227db96d56Sopenharmony_ci    Py_XDECREF(result);
7237db96d56Sopenharmony_ci    Py_DECREF(it);
7247db96d56Sopenharmony_ci    return NULL;
7257db96d56Sopenharmony_ci}
7267db96d56Sopenharmony_ci
7277db96d56Sopenharmony_ciPyDoc_STRVAR(functools_reduce_doc,
7287db96d56Sopenharmony_ci"reduce(function, iterable[, initial]) -> value\n\
7297db96d56Sopenharmony_ci\n\
7307db96d56Sopenharmony_ciApply a function of two arguments cumulatively to the items of a sequence\n\
7317db96d56Sopenharmony_cior iterable, from left to right, so as to reduce the iterable to a single\n\
7327db96d56Sopenharmony_civalue.  For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
7337db96d56Sopenharmony_ci((((1+2)+3)+4)+5).  If initial is present, it is placed before the items\n\
7347db96d56Sopenharmony_ciof the iterable in the calculation, and serves as a default when the\n\
7357db96d56Sopenharmony_ciiterable is empty.");
7367db96d56Sopenharmony_ci
7377db96d56Sopenharmony_ci/* lru_cache object **********************************************************/
7387db96d56Sopenharmony_ci
7397db96d56Sopenharmony_ci/* There are four principal algorithmic differences from the pure python version:
7407db96d56Sopenharmony_ci
7417db96d56Sopenharmony_ci   1). The C version relies on the GIL instead of having its own reentrant lock.
7427db96d56Sopenharmony_ci
7437db96d56Sopenharmony_ci   2). The prev/next link fields use borrowed references.
7447db96d56Sopenharmony_ci
7457db96d56Sopenharmony_ci   3). For a full cache, the pure python version rotates the location of the
7467db96d56Sopenharmony_ci       root entry so that it never has to move individual links and it can
7477db96d56Sopenharmony_ci       limit updates to just the key and result fields.  However, in the C
7487db96d56Sopenharmony_ci       version, links are temporarily removed while the cache dict updates are
7497db96d56Sopenharmony_ci       occurring. Afterwards, they are appended or prepended back into the
7507db96d56Sopenharmony_ci       doubly-linked lists.
7517db96d56Sopenharmony_ci
7527db96d56Sopenharmony_ci   4)  In the Python version, the _HashSeq class is used to prevent __hash__
7537db96d56Sopenharmony_ci       from being called more than once.  In the C version, the "known hash"
7547db96d56Sopenharmony_ci       variants of dictionary calls as used to the same effect.
7557db96d56Sopenharmony_ci
7567db96d56Sopenharmony_ci*/
7577db96d56Sopenharmony_ci
7587db96d56Sopenharmony_cistruct lru_list_elem;
7597db96d56Sopenharmony_cistruct lru_cache_object;
7607db96d56Sopenharmony_ci
7617db96d56Sopenharmony_citypedef struct lru_list_elem {
7627db96d56Sopenharmony_ci    PyObject_HEAD
7637db96d56Sopenharmony_ci    struct lru_list_elem *prev, *next;  /* borrowed links */
7647db96d56Sopenharmony_ci    Py_hash_t hash;
7657db96d56Sopenharmony_ci    PyObject *key, *result;
7667db96d56Sopenharmony_ci} lru_list_elem;
7677db96d56Sopenharmony_ci
7687db96d56Sopenharmony_cistatic void
7697db96d56Sopenharmony_cilru_list_elem_dealloc(lru_list_elem *link)
7707db96d56Sopenharmony_ci{
7717db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(link);
7727db96d56Sopenharmony_ci    Py_XDECREF(link->key);
7737db96d56Sopenharmony_ci    Py_XDECREF(link->result);
7747db96d56Sopenharmony_ci    tp->tp_free(link);
7757db96d56Sopenharmony_ci    Py_DECREF(tp);
7767db96d56Sopenharmony_ci}
7777db96d56Sopenharmony_ci
7787db96d56Sopenharmony_cistatic PyType_Slot lru_list_elem_type_slots[] = {
7797db96d56Sopenharmony_ci    {Py_tp_dealloc, lru_list_elem_dealloc},
7807db96d56Sopenharmony_ci    {0, 0}
7817db96d56Sopenharmony_ci};
7827db96d56Sopenharmony_ci
7837db96d56Sopenharmony_cistatic PyType_Spec lru_list_elem_type_spec = {
7847db96d56Sopenharmony_ci    .name = "functools._lru_list_elem",
7857db96d56Sopenharmony_ci    .basicsize = sizeof(lru_list_elem),
7867db96d56Sopenharmony_ci    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
7877db96d56Sopenharmony_ci             Py_TPFLAGS_IMMUTABLETYPE,
7887db96d56Sopenharmony_ci    .slots = lru_list_elem_type_slots
7897db96d56Sopenharmony_ci};
7907db96d56Sopenharmony_ci
7917db96d56Sopenharmony_ci
7927db96d56Sopenharmony_citypedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
7937db96d56Sopenharmony_ci
7947db96d56Sopenharmony_citypedef struct lru_cache_object {
7957db96d56Sopenharmony_ci    lru_list_elem root;  /* includes PyObject_HEAD */
7967db96d56Sopenharmony_ci    lru_cache_ternaryfunc wrapper;
7977db96d56Sopenharmony_ci    int typed;
7987db96d56Sopenharmony_ci    PyObject *cache;
7997db96d56Sopenharmony_ci    Py_ssize_t hits;
8007db96d56Sopenharmony_ci    PyObject *func;
8017db96d56Sopenharmony_ci    Py_ssize_t maxsize;
8027db96d56Sopenharmony_ci    Py_ssize_t misses;
8037db96d56Sopenharmony_ci    /* the kwd_mark is used delimit args and keywords in the cache keys */
8047db96d56Sopenharmony_ci    PyObject *kwd_mark;
8057db96d56Sopenharmony_ci    PyTypeObject *lru_list_elem_type;
8067db96d56Sopenharmony_ci    PyObject *cache_info_type;
8077db96d56Sopenharmony_ci    PyObject *dict;
8087db96d56Sopenharmony_ci    PyObject *weakreflist;
8097db96d56Sopenharmony_ci} lru_cache_object;
8107db96d56Sopenharmony_ci
8117db96d56Sopenharmony_cistatic PyObject *
8127db96d56Sopenharmony_cilru_cache_make_key(PyObject *kwd_mark, PyObject *args,
8137db96d56Sopenharmony_ci                   PyObject *kwds, int typed)
8147db96d56Sopenharmony_ci{
8157db96d56Sopenharmony_ci    PyObject *key, *keyword, *value;
8167db96d56Sopenharmony_ci    Py_ssize_t key_size, pos, key_pos, kwds_size;
8177db96d56Sopenharmony_ci
8187db96d56Sopenharmony_ci    kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
8197db96d56Sopenharmony_ci
8207db96d56Sopenharmony_ci    /* short path, key will match args anyway, which is a tuple */
8217db96d56Sopenharmony_ci    if (!typed && !kwds_size) {
8227db96d56Sopenharmony_ci        if (PyTuple_GET_SIZE(args) == 1) {
8237db96d56Sopenharmony_ci            key = PyTuple_GET_ITEM(args, 0);
8247db96d56Sopenharmony_ci            if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) {
8257db96d56Sopenharmony_ci                /* For common scalar keys, save space by
8267db96d56Sopenharmony_ci                   dropping the enclosing args tuple  */
8277db96d56Sopenharmony_ci                Py_INCREF(key);
8287db96d56Sopenharmony_ci                return key;
8297db96d56Sopenharmony_ci            }
8307db96d56Sopenharmony_ci        }
8317db96d56Sopenharmony_ci        Py_INCREF(args);
8327db96d56Sopenharmony_ci        return args;
8337db96d56Sopenharmony_ci    }
8347db96d56Sopenharmony_ci
8357db96d56Sopenharmony_ci    key_size = PyTuple_GET_SIZE(args);
8367db96d56Sopenharmony_ci    if (kwds_size)
8377db96d56Sopenharmony_ci        key_size += kwds_size * 2 + 1;
8387db96d56Sopenharmony_ci    if (typed)
8397db96d56Sopenharmony_ci        key_size += PyTuple_GET_SIZE(args) + kwds_size;
8407db96d56Sopenharmony_ci
8417db96d56Sopenharmony_ci    key = PyTuple_New(key_size);
8427db96d56Sopenharmony_ci    if (key == NULL)
8437db96d56Sopenharmony_ci        return NULL;
8447db96d56Sopenharmony_ci
8457db96d56Sopenharmony_ci    key_pos = 0;
8467db96d56Sopenharmony_ci    for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
8477db96d56Sopenharmony_ci        PyObject *item = PyTuple_GET_ITEM(args, pos);
8487db96d56Sopenharmony_ci        Py_INCREF(item);
8497db96d56Sopenharmony_ci        PyTuple_SET_ITEM(key, key_pos++, item);
8507db96d56Sopenharmony_ci    }
8517db96d56Sopenharmony_ci    if (kwds_size) {
8527db96d56Sopenharmony_ci        Py_INCREF(kwd_mark);
8537db96d56Sopenharmony_ci        PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
8547db96d56Sopenharmony_ci        for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
8557db96d56Sopenharmony_ci            Py_INCREF(keyword);
8567db96d56Sopenharmony_ci            PyTuple_SET_ITEM(key, key_pos++, keyword);
8577db96d56Sopenharmony_ci            Py_INCREF(value);
8587db96d56Sopenharmony_ci            PyTuple_SET_ITEM(key, key_pos++, value);
8597db96d56Sopenharmony_ci        }
8607db96d56Sopenharmony_ci        assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
8617db96d56Sopenharmony_ci    }
8627db96d56Sopenharmony_ci    if (typed) {
8637db96d56Sopenharmony_ci        for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
8647db96d56Sopenharmony_ci            PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
8657db96d56Sopenharmony_ci            Py_INCREF(item);
8667db96d56Sopenharmony_ci            PyTuple_SET_ITEM(key, key_pos++, item);
8677db96d56Sopenharmony_ci        }
8687db96d56Sopenharmony_ci        if (kwds_size) {
8697db96d56Sopenharmony_ci            for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
8707db96d56Sopenharmony_ci                PyObject *item = (PyObject *)Py_TYPE(value);
8717db96d56Sopenharmony_ci                Py_INCREF(item);
8727db96d56Sopenharmony_ci                PyTuple_SET_ITEM(key, key_pos++, item);
8737db96d56Sopenharmony_ci            }
8747db96d56Sopenharmony_ci        }
8757db96d56Sopenharmony_ci    }
8767db96d56Sopenharmony_ci    assert(key_pos == key_size);
8777db96d56Sopenharmony_ci    return key;
8787db96d56Sopenharmony_ci}
8797db96d56Sopenharmony_ci
8807db96d56Sopenharmony_cistatic PyObject *
8817db96d56Sopenharmony_ciuncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
8827db96d56Sopenharmony_ci{
8837db96d56Sopenharmony_ci    PyObject *result;
8847db96d56Sopenharmony_ci
8857db96d56Sopenharmony_ci    self->misses++;
8867db96d56Sopenharmony_ci    result = PyObject_Call(self->func, args, kwds);
8877db96d56Sopenharmony_ci    if (!result)
8887db96d56Sopenharmony_ci        return NULL;
8897db96d56Sopenharmony_ci    return result;
8907db96d56Sopenharmony_ci}
8917db96d56Sopenharmony_ci
8927db96d56Sopenharmony_cistatic PyObject *
8937db96d56Sopenharmony_ciinfinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
8947db96d56Sopenharmony_ci{
8957db96d56Sopenharmony_ci    PyObject *result;
8967db96d56Sopenharmony_ci    Py_hash_t hash;
8977db96d56Sopenharmony_ci    PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
8987db96d56Sopenharmony_ci    if (!key)
8997db96d56Sopenharmony_ci        return NULL;
9007db96d56Sopenharmony_ci    hash = PyObject_Hash(key);
9017db96d56Sopenharmony_ci    if (hash == -1) {
9027db96d56Sopenharmony_ci        Py_DECREF(key);
9037db96d56Sopenharmony_ci        return NULL;
9047db96d56Sopenharmony_ci    }
9057db96d56Sopenharmony_ci    result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
9067db96d56Sopenharmony_ci    if (result) {
9077db96d56Sopenharmony_ci        Py_INCREF(result);
9087db96d56Sopenharmony_ci        self->hits++;
9097db96d56Sopenharmony_ci        Py_DECREF(key);
9107db96d56Sopenharmony_ci        return result;
9117db96d56Sopenharmony_ci    }
9127db96d56Sopenharmony_ci    if (PyErr_Occurred()) {
9137db96d56Sopenharmony_ci        Py_DECREF(key);
9147db96d56Sopenharmony_ci        return NULL;
9157db96d56Sopenharmony_ci    }
9167db96d56Sopenharmony_ci    self->misses++;
9177db96d56Sopenharmony_ci    result = PyObject_Call(self->func, args, kwds);
9187db96d56Sopenharmony_ci    if (!result) {
9197db96d56Sopenharmony_ci        Py_DECREF(key);
9207db96d56Sopenharmony_ci        return NULL;
9217db96d56Sopenharmony_ci    }
9227db96d56Sopenharmony_ci    if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
9237db96d56Sopenharmony_ci        Py_DECREF(result);
9247db96d56Sopenharmony_ci        Py_DECREF(key);
9257db96d56Sopenharmony_ci        return NULL;
9267db96d56Sopenharmony_ci    }
9277db96d56Sopenharmony_ci    Py_DECREF(key);
9287db96d56Sopenharmony_ci    return result;
9297db96d56Sopenharmony_ci}
9307db96d56Sopenharmony_ci
9317db96d56Sopenharmony_cistatic void
9327db96d56Sopenharmony_cilru_cache_extract_link(lru_list_elem *link)
9337db96d56Sopenharmony_ci{
9347db96d56Sopenharmony_ci    lru_list_elem *link_prev = link->prev;
9357db96d56Sopenharmony_ci    lru_list_elem *link_next = link->next;
9367db96d56Sopenharmony_ci    link_prev->next = link->next;
9377db96d56Sopenharmony_ci    link_next->prev = link->prev;
9387db96d56Sopenharmony_ci}
9397db96d56Sopenharmony_ci
9407db96d56Sopenharmony_cistatic void
9417db96d56Sopenharmony_cilru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
9427db96d56Sopenharmony_ci{
9437db96d56Sopenharmony_ci    lru_list_elem *root = &self->root;
9447db96d56Sopenharmony_ci    lru_list_elem *last = root->prev;
9457db96d56Sopenharmony_ci    last->next = root->prev = link;
9467db96d56Sopenharmony_ci    link->prev = last;
9477db96d56Sopenharmony_ci    link->next = root;
9487db96d56Sopenharmony_ci}
9497db96d56Sopenharmony_ci
9507db96d56Sopenharmony_cistatic void
9517db96d56Sopenharmony_cilru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
9527db96d56Sopenharmony_ci{
9537db96d56Sopenharmony_ci    lru_list_elem *root = &self->root;
9547db96d56Sopenharmony_ci    lru_list_elem *first = root->next;
9557db96d56Sopenharmony_ci    first->prev = root->next = link;
9567db96d56Sopenharmony_ci    link->prev = root;
9577db96d56Sopenharmony_ci    link->next = first;
9587db96d56Sopenharmony_ci}
9597db96d56Sopenharmony_ci
9607db96d56Sopenharmony_ci/* General note on reentrancy:
9617db96d56Sopenharmony_ci
9627db96d56Sopenharmony_ci   There are four dictionary calls in the bounded_lru_cache_wrapper():
9637db96d56Sopenharmony_ci   1) The initial check for a cache match.  2) The post user-function
9647db96d56Sopenharmony_ci   check for a cache match.  3) The deletion of the oldest entry.
9657db96d56Sopenharmony_ci   4) The addition of the newest entry.
9667db96d56Sopenharmony_ci
9677db96d56Sopenharmony_ci   In all four calls, we have a known hash which lets use avoid a call
9687db96d56Sopenharmony_ci   to __hash__().  That leaves only __eq__ as a possible source of a
9697db96d56Sopenharmony_ci   reentrant call.
9707db96d56Sopenharmony_ci
9717db96d56Sopenharmony_ci   The __eq__ method call is always made for a cache hit (dict access #1).
9727db96d56Sopenharmony_ci   Accordingly, we have make sure not modify the cache state prior to
9737db96d56Sopenharmony_ci   this call.
9747db96d56Sopenharmony_ci
9757db96d56Sopenharmony_ci   The __eq__ method call is never made for the deletion (dict access #3)
9767db96d56Sopenharmony_ci   because it is an identity match.
9777db96d56Sopenharmony_ci
9787db96d56Sopenharmony_ci   For the other two accesses (#2 and #4), calls to __eq__ only occur
9797db96d56Sopenharmony_ci   when some other entry happens to have an exactly matching hash (all
9807db96d56Sopenharmony_ci   64-bits).  Though rare, this can happen, so we have to make sure to
9817db96d56Sopenharmony_ci   either call it at the top of its code path before any cache
9827db96d56Sopenharmony_ci   state modifications (dict access #2) or be prepared to restore
9837db96d56Sopenharmony_ci   invariants at the end of the code path (dict access #4).
9847db96d56Sopenharmony_ci
9857db96d56Sopenharmony_ci   Another possible source of reentrancy is a decref which can trigger
9867db96d56Sopenharmony_ci   arbitrary code execution.  To make the code easier to reason about,
9877db96d56Sopenharmony_ci   the decrefs are deferred to the end of the each possible code path
9887db96d56Sopenharmony_ci   so that we know the cache is a consistent state.
9897db96d56Sopenharmony_ci */
9907db96d56Sopenharmony_ci
9917db96d56Sopenharmony_cistatic PyObject *
9927db96d56Sopenharmony_cibounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
9937db96d56Sopenharmony_ci{
9947db96d56Sopenharmony_ci    lru_list_elem *link;
9957db96d56Sopenharmony_ci    PyObject *key, *result, *testresult;
9967db96d56Sopenharmony_ci    Py_hash_t hash;
9977db96d56Sopenharmony_ci
9987db96d56Sopenharmony_ci    key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
9997db96d56Sopenharmony_ci    if (!key)
10007db96d56Sopenharmony_ci        return NULL;
10017db96d56Sopenharmony_ci    hash = PyObject_Hash(key);
10027db96d56Sopenharmony_ci    if (hash == -1) {
10037db96d56Sopenharmony_ci        Py_DECREF(key);
10047db96d56Sopenharmony_ci        return NULL;
10057db96d56Sopenharmony_ci    }
10067db96d56Sopenharmony_ci    link  = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
10077db96d56Sopenharmony_ci    if (link != NULL) {
10087db96d56Sopenharmony_ci        lru_cache_extract_link(link);
10097db96d56Sopenharmony_ci        lru_cache_append_link(self, link);
10107db96d56Sopenharmony_ci        result = link->result;
10117db96d56Sopenharmony_ci        self->hits++;
10127db96d56Sopenharmony_ci        Py_INCREF(result);
10137db96d56Sopenharmony_ci        Py_DECREF(key);
10147db96d56Sopenharmony_ci        return result;
10157db96d56Sopenharmony_ci    }
10167db96d56Sopenharmony_ci    if (PyErr_Occurred()) {
10177db96d56Sopenharmony_ci        Py_DECREF(key);
10187db96d56Sopenharmony_ci        return NULL;
10197db96d56Sopenharmony_ci    }
10207db96d56Sopenharmony_ci    self->misses++;
10217db96d56Sopenharmony_ci    result = PyObject_Call(self->func, args, kwds);
10227db96d56Sopenharmony_ci    if (!result) {
10237db96d56Sopenharmony_ci        Py_DECREF(key);
10247db96d56Sopenharmony_ci        return NULL;
10257db96d56Sopenharmony_ci    }
10267db96d56Sopenharmony_ci    testresult = _PyDict_GetItem_KnownHash(self->cache, key, hash);
10277db96d56Sopenharmony_ci    if (testresult != NULL) {
10287db96d56Sopenharmony_ci        /* Getting here means that this same key was added to the cache
10297db96d56Sopenharmony_ci           during the PyObject_Call().  Since the link update is already
10307db96d56Sopenharmony_ci           done, we need only return the computed result. */
10317db96d56Sopenharmony_ci        Py_DECREF(key);
10327db96d56Sopenharmony_ci        return result;
10337db96d56Sopenharmony_ci    }
10347db96d56Sopenharmony_ci    if (PyErr_Occurred()) {
10357db96d56Sopenharmony_ci        /* This is an unusual case since this same lookup
10367db96d56Sopenharmony_ci           did not previously trigger an error during lookup.
10377db96d56Sopenharmony_ci           Treat it the same as an error in user function
10387db96d56Sopenharmony_ci           and return with the error set. */
10397db96d56Sopenharmony_ci        Py_DECREF(key);
10407db96d56Sopenharmony_ci        Py_DECREF(result);
10417db96d56Sopenharmony_ci        return NULL;
10427db96d56Sopenharmony_ci    }
10437db96d56Sopenharmony_ci    /* This is the normal case.  The new key wasn't found before
10447db96d56Sopenharmony_ci       user function call and it is still not there.  So we
10457db96d56Sopenharmony_ci       proceed normally and update the cache with the new result. */
10467db96d56Sopenharmony_ci
10477db96d56Sopenharmony_ci    assert(self->maxsize > 0);
10487db96d56Sopenharmony_ci    if (PyDict_GET_SIZE(self->cache) < self->maxsize ||
10497db96d56Sopenharmony_ci        self->root.next == &self->root)
10507db96d56Sopenharmony_ci    {
10517db96d56Sopenharmony_ci        /* Cache is not full, so put the result in a new link */
10527db96d56Sopenharmony_ci        link = (lru_list_elem *)PyObject_New(lru_list_elem,
10537db96d56Sopenharmony_ci                                             self->lru_list_elem_type);
10547db96d56Sopenharmony_ci        if (link == NULL) {
10557db96d56Sopenharmony_ci            Py_DECREF(key);
10567db96d56Sopenharmony_ci            Py_DECREF(result);
10577db96d56Sopenharmony_ci            return NULL;
10587db96d56Sopenharmony_ci        }
10597db96d56Sopenharmony_ci
10607db96d56Sopenharmony_ci        link->hash = hash;
10617db96d56Sopenharmony_ci        link->key = key;
10627db96d56Sopenharmony_ci        link->result = result;
10637db96d56Sopenharmony_ci        /* What is really needed here is a SetItem variant with a "no clobber"
10647db96d56Sopenharmony_ci           option.  If the __eq__ call triggers a reentrant call that adds
10657db96d56Sopenharmony_ci           this same key, then this setitem call will update the cache dict
10667db96d56Sopenharmony_ci           with this new link, leaving the old link as an orphan (i.e. not
10677db96d56Sopenharmony_ci           having a cache dict entry that refers to it). */
10687db96d56Sopenharmony_ci        if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
10697db96d56Sopenharmony_ci                                      hash) < 0) {
10707db96d56Sopenharmony_ci            Py_DECREF(link);
10717db96d56Sopenharmony_ci            return NULL;
10727db96d56Sopenharmony_ci        }
10737db96d56Sopenharmony_ci        lru_cache_append_link(self, link);
10747db96d56Sopenharmony_ci        Py_INCREF(result); /* for return */
10757db96d56Sopenharmony_ci        return result;
10767db96d56Sopenharmony_ci    }
10777db96d56Sopenharmony_ci    /* Since the cache is full, we need to evict an old key and add
10787db96d56Sopenharmony_ci       a new key.  Rather than free the old link and allocate a new
10797db96d56Sopenharmony_ci       one, we reuse the link for the new key and result and move it
10807db96d56Sopenharmony_ci       to front of the cache to mark it as recently used.
10817db96d56Sopenharmony_ci
10827db96d56Sopenharmony_ci       We try to assure all code paths (including errors) leave all
10837db96d56Sopenharmony_ci       of the links in place.  Either the link is successfully
10847db96d56Sopenharmony_ci       updated and moved or it is restored to its old position.
10857db96d56Sopenharmony_ci       However if an unrecoverable error is found, it doesn't
10867db96d56Sopenharmony_ci       make sense to reinsert the link, so we leave it out
10877db96d56Sopenharmony_ci       and the cache will no longer register as full.
10887db96d56Sopenharmony_ci    */
10897db96d56Sopenharmony_ci    PyObject *oldkey, *oldresult, *popresult;
10907db96d56Sopenharmony_ci
10917db96d56Sopenharmony_ci    /* Extract the oldest item. */
10927db96d56Sopenharmony_ci    assert(self->root.next != &self->root);
10937db96d56Sopenharmony_ci    link = self->root.next;
10947db96d56Sopenharmony_ci    lru_cache_extract_link(link);
10957db96d56Sopenharmony_ci    /* Remove it from the cache.
10967db96d56Sopenharmony_ci       The cache dict holds one reference to the link.
10977db96d56Sopenharmony_ci       We created one other reference when the link was created.
10987db96d56Sopenharmony_ci       The linked list only has borrowed references. */
10997db96d56Sopenharmony_ci    popresult = _PyDict_Pop_KnownHash(self->cache, link->key,
11007db96d56Sopenharmony_ci                                      link->hash, Py_None);
11017db96d56Sopenharmony_ci    if (popresult == Py_None) {
11027db96d56Sopenharmony_ci        /* Getting here means that the user function call or another
11037db96d56Sopenharmony_ci           thread has already removed the old key from the dictionary.
11047db96d56Sopenharmony_ci           This link is now an orphan.  Since we don't want to leave the
11057db96d56Sopenharmony_ci           cache in an inconsistent state, we don't restore the link. */
11067db96d56Sopenharmony_ci        Py_DECREF(popresult);
11077db96d56Sopenharmony_ci        Py_DECREF(link);
11087db96d56Sopenharmony_ci        Py_DECREF(key);
11097db96d56Sopenharmony_ci        return result;
11107db96d56Sopenharmony_ci    }
11117db96d56Sopenharmony_ci    if (popresult == NULL) {
11127db96d56Sopenharmony_ci        /* An error arose while trying to remove the oldest key (the one
11137db96d56Sopenharmony_ci           being evicted) from the cache.  We restore the link to its
11147db96d56Sopenharmony_ci           original position as the oldest link.  Then we allow the
11157db96d56Sopenharmony_ci           error propagate upward; treating it the same as an error
11167db96d56Sopenharmony_ci           arising in the user function. */
11177db96d56Sopenharmony_ci        lru_cache_prepend_link(self, link);
11187db96d56Sopenharmony_ci        Py_DECREF(key);
11197db96d56Sopenharmony_ci        Py_DECREF(result);
11207db96d56Sopenharmony_ci        return NULL;
11217db96d56Sopenharmony_ci    }
11227db96d56Sopenharmony_ci    /* Keep a reference to the old key and old result to prevent their
11237db96d56Sopenharmony_ci       ref counts from going to zero during the update. That will
11247db96d56Sopenharmony_ci       prevent potentially arbitrary object clean-up code (i.e. __del__)
11257db96d56Sopenharmony_ci       from running while we're still adjusting the links. */
11267db96d56Sopenharmony_ci    oldkey = link->key;
11277db96d56Sopenharmony_ci    oldresult = link->result;
11287db96d56Sopenharmony_ci
11297db96d56Sopenharmony_ci    link->hash = hash;
11307db96d56Sopenharmony_ci    link->key = key;
11317db96d56Sopenharmony_ci    link->result = result;
11327db96d56Sopenharmony_ci    /* Note:  The link is being added to the cache dict without the
11337db96d56Sopenharmony_ci       prev and next fields set to valid values.   We have to wait
11347db96d56Sopenharmony_ci       for successful insertion in the cache dict before adding the
11357db96d56Sopenharmony_ci       link to the linked list.  Otherwise, the potentially reentrant
11367db96d56Sopenharmony_ci       __eq__ call could cause the then orphan link to be visited. */
11377db96d56Sopenharmony_ci    if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
11387db96d56Sopenharmony_ci                                  hash) < 0) {
11397db96d56Sopenharmony_ci        /* Somehow the cache dict update failed.  We no longer can
11407db96d56Sopenharmony_ci           restore the old link.  Let the error propagate upward and
11417db96d56Sopenharmony_ci           leave the cache short one link. */
11427db96d56Sopenharmony_ci        Py_DECREF(popresult);
11437db96d56Sopenharmony_ci        Py_DECREF(link);
11447db96d56Sopenharmony_ci        Py_DECREF(oldkey);
11457db96d56Sopenharmony_ci        Py_DECREF(oldresult);
11467db96d56Sopenharmony_ci        return NULL;
11477db96d56Sopenharmony_ci    }
11487db96d56Sopenharmony_ci    lru_cache_append_link(self, link);
11497db96d56Sopenharmony_ci    Py_INCREF(result); /* for return */
11507db96d56Sopenharmony_ci    Py_DECREF(popresult);
11517db96d56Sopenharmony_ci    Py_DECREF(oldkey);
11527db96d56Sopenharmony_ci    Py_DECREF(oldresult);
11537db96d56Sopenharmony_ci    return result;
11547db96d56Sopenharmony_ci}
11557db96d56Sopenharmony_ci
11567db96d56Sopenharmony_cistatic PyObject *
11577db96d56Sopenharmony_cilru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
11587db96d56Sopenharmony_ci{
11597db96d56Sopenharmony_ci    PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
11607db96d56Sopenharmony_ci    int typed;
11617db96d56Sopenharmony_ci    lru_cache_object *obj;
11627db96d56Sopenharmony_ci    Py_ssize_t maxsize;
11637db96d56Sopenharmony_ci    PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
11647db96d56Sopenharmony_ci    _functools_state *state;
11657db96d56Sopenharmony_ci    static char *keywords[] = {"user_function", "maxsize", "typed",
11667db96d56Sopenharmony_ci                               "cache_info_type", NULL};
11677db96d56Sopenharmony_ci
11687db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
11697db96d56Sopenharmony_ci                                     &func, &maxsize_O, &typed,
11707db96d56Sopenharmony_ci                                     &cache_info_type)) {
11717db96d56Sopenharmony_ci        return NULL;
11727db96d56Sopenharmony_ci    }
11737db96d56Sopenharmony_ci
11747db96d56Sopenharmony_ci    if (!PyCallable_Check(func)) {
11757db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
11767db96d56Sopenharmony_ci                        "the first argument must be callable");
11777db96d56Sopenharmony_ci        return NULL;
11787db96d56Sopenharmony_ci    }
11797db96d56Sopenharmony_ci
11807db96d56Sopenharmony_ci    state = get_functools_state_by_type(type);
11817db96d56Sopenharmony_ci    if (state == NULL) {
11827db96d56Sopenharmony_ci        return NULL;
11837db96d56Sopenharmony_ci    }
11847db96d56Sopenharmony_ci
11857db96d56Sopenharmony_ci    /* select the caching function, and make/inc maxsize_O */
11867db96d56Sopenharmony_ci    if (maxsize_O == Py_None) {
11877db96d56Sopenharmony_ci        wrapper = infinite_lru_cache_wrapper;
11887db96d56Sopenharmony_ci        /* use this only to initialize lru_cache_object attribute maxsize */
11897db96d56Sopenharmony_ci        maxsize = -1;
11907db96d56Sopenharmony_ci    } else if (PyIndex_Check(maxsize_O)) {
11917db96d56Sopenharmony_ci        maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
11927db96d56Sopenharmony_ci        if (maxsize == -1 && PyErr_Occurred())
11937db96d56Sopenharmony_ci            return NULL;
11947db96d56Sopenharmony_ci        if (maxsize < 0) {
11957db96d56Sopenharmony_ci            maxsize = 0;
11967db96d56Sopenharmony_ci        }
11977db96d56Sopenharmony_ci        if (maxsize == 0)
11987db96d56Sopenharmony_ci            wrapper = uncached_lru_cache_wrapper;
11997db96d56Sopenharmony_ci        else
12007db96d56Sopenharmony_ci            wrapper = bounded_lru_cache_wrapper;
12017db96d56Sopenharmony_ci    } else {
12027db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
12037db96d56Sopenharmony_ci        return NULL;
12047db96d56Sopenharmony_ci    }
12057db96d56Sopenharmony_ci
12067db96d56Sopenharmony_ci    if (!(cachedict = PyDict_New()))
12077db96d56Sopenharmony_ci        return NULL;
12087db96d56Sopenharmony_ci
12097db96d56Sopenharmony_ci    obj = (lru_cache_object *)type->tp_alloc(type, 0);
12107db96d56Sopenharmony_ci    if (obj == NULL) {
12117db96d56Sopenharmony_ci        Py_DECREF(cachedict);
12127db96d56Sopenharmony_ci        return NULL;
12137db96d56Sopenharmony_ci    }
12147db96d56Sopenharmony_ci
12157db96d56Sopenharmony_ci    obj->root.prev = &obj->root;
12167db96d56Sopenharmony_ci    obj->root.next = &obj->root;
12177db96d56Sopenharmony_ci    obj->wrapper = wrapper;
12187db96d56Sopenharmony_ci    obj->typed = typed;
12197db96d56Sopenharmony_ci    obj->cache = cachedict;
12207db96d56Sopenharmony_ci    Py_INCREF(func);
12217db96d56Sopenharmony_ci    obj->func = func;
12227db96d56Sopenharmony_ci    obj->misses = obj->hits = 0;
12237db96d56Sopenharmony_ci    obj->maxsize = maxsize;
12247db96d56Sopenharmony_ci    Py_INCREF(state->kwd_mark);
12257db96d56Sopenharmony_ci    obj->kwd_mark = state->kwd_mark;
12267db96d56Sopenharmony_ci    Py_INCREF(state->lru_list_elem_type);
12277db96d56Sopenharmony_ci    obj->lru_list_elem_type = state->lru_list_elem_type;
12287db96d56Sopenharmony_ci    Py_INCREF(cache_info_type);
12297db96d56Sopenharmony_ci    obj->cache_info_type = cache_info_type;
12307db96d56Sopenharmony_ci    obj->dict = NULL;
12317db96d56Sopenharmony_ci    obj->weakreflist = NULL;
12327db96d56Sopenharmony_ci    return (PyObject *)obj;
12337db96d56Sopenharmony_ci}
12347db96d56Sopenharmony_ci
12357db96d56Sopenharmony_cistatic lru_list_elem *
12367db96d56Sopenharmony_cilru_cache_unlink_list(lru_cache_object *self)
12377db96d56Sopenharmony_ci{
12387db96d56Sopenharmony_ci    lru_list_elem *root = &self->root;
12397db96d56Sopenharmony_ci    lru_list_elem *link = root->next;
12407db96d56Sopenharmony_ci    if (link == root)
12417db96d56Sopenharmony_ci        return NULL;
12427db96d56Sopenharmony_ci    root->prev->next = NULL;
12437db96d56Sopenharmony_ci    root->next = root->prev = root;
12447db96d56Sopenharmony_ci    return link;
12457db96d56Sopenharmony_ci}
12467db96d56Sopenharmony_ci
12477db96d56Sopenharmony_cistatic void
12487db96d56Sopenharmony_cilru_cache_clear_list(lru_list_elem *link)
12497db96d56Sopenharmony_ci{
12507db96d56Sopenharmony_ci    while (link != NULL) {
12517db96d56Sopenharmony_ci        lru_list_elem *next = link->next;
12527db96d56Sopenharmony_ci        Py_DECREF(link);
12537db96d56Sopenharmony_ci        link = next;
12547db96d56Sopenharmony_ci    }
12557db96d56Sopenharmony_ci}
12567db96d56Sopenharmony_ci
12577db96d56Sopenharmony_cistatic int
12587db96d56Sopenharmony_cilru_cache_tp_clear(lru_cache_object *self)
12597db96d56Sopenharmony_ci{
12607db96d56Sopenharmony_ci    lru_list_elem *list = lru_cache_unlink_list(self);
12617db96d56Sopenharmony_ci    Py_CLEAR(self->cache);
12627db96d56Sopenharmony_ci    Py_CLEAR(self->func);
12637db96d56Sopenharmony_ci    Py_CLEAR(self->kwd_mark);
12647db96d56Sopenharmony_ci    Py_CLEAR(self->lru_list_elem_type);
12657db96d56Sopenharmony_ci    Py_CLEAR(self->cache_info_type);
12667db96d56Sopenharmony_ci    Py_CLEAR(self->dict);
12677db96d56Sopenharmony_ci    lru_cache_clear_list(list);
12687db96d56Sopenharmony_ci    return 0;
12697db96d56Sopenharmony_ci}
12707db96d56Sopenharmony_ci
12717db96d56Sopenharmony_cistatic void
12727db96d56Sopenharmony_cilru_cache_dealloc(lru_cache_object *obj)
12737db96d56Sopenharmony_ci{
12747db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(obj);
12757db96d56Sopenharmony_ci    /* bpo-31095: UnTrack is needed before calling any callbacks */
12767db96d56Sopenharmony_ci    PyObject_GC_UnTrack(obj);
12777db96d56Sopenharmony_ci    if (obj->weakreflist != NULL) {
12787db96d56Sopenharmony_ci        PyObject_ClearWeakRefs((PyObject*)obj);
12797db96d56Sopenharmony_ci    }
12807db96d56Sopenharmony_ci
12817db96d56Sopenharmony_ci    (void)lru_cache_tp_clear(obj);
12827db96d56Sopenharmony_ci    tp->tp_free(obj);
12837db96d56Sopenharmony_ci    Py_DECREF(tp);
12847db96d56Sopenharmony_ci}
12857db96d56Sopenharmony_ci
12867db96d56Sopenharmony_cistatic PyObject *
12877db96d56Sopenharmony_cilru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
12887db96d56Sopenharmony_ci{
12897db96d56Sopenharmony_ci    return self->wrapper(self, args, kwds);
12907db96d56Sopenharmony_ci}
12917db96d56Sopenharmony_ci
12927db96d56Sopenharmony_cistatic PyObject *
12937db96d56Sopenharmony_cilru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
12947db96d56Sopenharmony_ci{
12957db96d56Sopenharmony_ci    if (obj == Py_None || obj == NULL) {
12967db96d56Sopenharmony_ci        Py_INCREF(self);
12977db96d56Sopenharmony_ci        return self;
12987db96d56Sopenharmony_ci    }
12997db96d56Sopenharmony_ci    return PyMethod_New(self, obj);
13007db96d56Sopenharmony_ci}
13017db96d56Sopenharmony_ci
13027db96d56Sopenharmony_cistatic PyObject *
13037db96d56Sopenharmony_cilru_cache_cache_info(lru_cache_object *self, PyObject *unused)
13047db96d56Sopenharmony_ci{
13057db96d56Sopenharmony_ci    if (self->maxsize == -1) {
13067db96d56Sopenharmony_ci        return PyObject_CallFunction(self->cache_info_type, "nnOn",
13077db96d56Sopenharmony_ci                                     self->hits, self->misses, Py_None,
13087db96d56Sopenharmony_ci                                     PyDict_GET_SIZE(self->cache));
13097db96d56Sopenharmony_ci    }
13107db96d56Sopenharmony_ci    return PyObject_CallFunction(self->cache_info_type, "nnnn",
13117db96d56Sopenharmony_ci                                 self->hits, self->misses, self->maxsize,
13127db96d56Sopenharmony_ci                                 PyDict_GET_SIZE(self->cache));
13137db96d56Sopenharmony_ci}
13147db96d56Sopenharmony_ci
13157db96d56Sopenharmony_cistatic PyObject *
13167db96d56Sopenharmony_cilru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
13177db96d56Sopenharmony_ci{
13187db96d56Sopenharmony_ci    lru_list_elem *list = lru_cache_unlink_list(self);
13197db96d56Sopenharmony_ci    self->hits = self->misses = 0;
13207db96d56Sopenharmony_ci    PyDict_Clear(self->cache);
13217db96d56Sopenharmony_ci    lru_cache_clear_list(list);
13227db96d56Sopenharmony_ci    Py_RETURN_NONE;
13237db96d56Sopenharmony_ci}
13247db96d56Sopenharmony_ci
13257db96d56Sopenharmony_cistatic PyObject *
13267db96d56Sopenharmony_cilru_cache_reduce(PyObject *self, PyObject *unused)
13277db96d56Sopenharmony_ci{
13287db96d56Sopenharmony_ci    return PyObject_GetAttrString(self, "__qualname__");
13297db96d56Sopenharmony_ci}
13307db96d56Sopenharmony_ci
13317db96d56Sopenharmony_cistatic PyObject *
13327db96d56Sopenharmony_cilru_cache_copy(PyObject *self, PyObject *unused)
13337db96d56Sopenharmony_ci{
13347db96d56Sopenharmony_ci    Py_INCREF(self);
13357db96d56Sopenharmony_ci    return self;
13367db96d56Sopenharmony_ci}
13377db96d56Sopenharmony_ci
13387db96d56Sopenharmony_cistatic PyObject *
13397db96d56Sopenharmony_cilru_cache_deepcopy(PyObject *self, PyObject *unused)
13407db96d56Sopenharmony_ci{
13417db96d56Sopenharmony_ci    Py_INCREF(self);
13427db96d56Sopenharmony_ci    return self;
13437db96d56Sopenharmony_ci}
13447db96d56Sopenharmony_ci
13457db96d56Sopenharmony_cistatic int
13467db96d56Sopenharmony_cilru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
13477db96d56Sopenharmony_ci{
13487db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(self));
13497db96d56Sopenharmony_ci    lru_list_elem *link = self->root.next;
13507db96d56Sopenharmony_ci    while (link != &self->root) {
13517db96d56Sopenharmony_ci        lru_list_elem *next = link->next;
13527db96d56Sopenharmony_ci        Py_VISIT(link->key);
13537db96d56Sopenharmony_ci        Py_VISIT(link->result);
13547db96d56Sopenharmony_ci        Py_VISIT(Py_TYPE(link));
13557db96d56Sopenharmony_ci        link = next;
13567db96d56Sopenharmony_ci    }
13577db96d56Sopenharmony_ci    Py_VISIT(self->cache);
13587db96d56Sopenharmony_ci    Py_VISIT(self->func);
13597db96d56Sopenharmony_ci    Py_VISIT(self->kwd_mark);
13607db96d56Sopenharmony_ci    Py_VISIT(self->lru_list_elem_type);
13617db96d56Sopenharmony_ci    Py_VISIT(self->cache_info_type);
13627db96d56Sopenharmony_ci    Py_VISIT(self->dict);
13637db96d56Sopenharmony_ci    return 0;
13647db96d56Sopenharmony_ci}
13657db96d56Sopenharmony_ci
13667db96d56Sopenharmony_ci
13677db96d56Sopenharmony_ciPyDoc_STRVAR(lru_cache_doc,
13687db96d56Sopenharmony_ci"Create a cached callable that wraps another function.\n\
13697db96d56Sopenharmony_ci\n\
13707db96d56Sopenharmony_ciuser_function:      the function being cached\n\
13717db96d56Sopenharmony_ci\n\
13727db96d56Sopenharmony_cimaxsize:  0         for no caching\n\
13737db96d56Sopenharmony_ci          None      for unlimited cache size\n\
13747db96d56Sopenharmony_ci          n         for a bounded cache\n\
13757db96d56Sopenharmony_ci\n\
13767db96d56Sopenharmony_cityped:    False     cache f(3) and f(3.0) as identical calls\n\
13777db96d56Sopenharmony_ci          True      cache f(3) and f(3.0) as distinct calls\n\
13787db96d56Sopenharmony_ci\n\
13797db96d56Sopenharmony_cicache_info_type:    namedtuple class with the fields:\n\
13807db96d56Sopenharmony_ci                        hits misses currsize maxsize\n"
13817db96d56Sopenharmony_ci);
13827db96d56Sopenharmony_ci
13837db96d56Sopenharmony_cistatic PyMethodDef lru_cache_methods[] = {
13847db96d56Sopenharmony_ci    {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
13857db96d56Sopenharmony_ci    {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
13867db96d56Sopenharmony_ci    {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
13877db96d56Sopenharmony_ci    {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
13887db96d56Sopenharmony_ci    {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
13897db96d56Sopenharmony_ci    {NULL}
13907db96d56Sopenharmony_ci};
13917db96d56Sopenharmony_ci
13927db96d56Sopenharmony_cistatic PyGetSetDef lru_cache_getsetlist[] = {
13937db96d56Sopenharmony_ci    {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
13947db96d56Sopenharmony_ci    {NULL}
13957db96d56Sopenharmony_ci};
13967db96d56Sopenharmony_ci
13977db96d56Sopenharmony_cistatic PyMemberDef lru_cache_memberlist[] = {
13987db96d56Sopenharmony_ci    {"__dictoffset__", T_PYSSIZET,
13997db96d56Sopenharmony_ci     offsetof(lru_cache_object, dict), READONLY},
14007db96d56Sopenharmony_ci    {"__weaklistoffset__", T_PYSSIZET,
14017db96d56Sopenharmony_ci     offsetof(lru_cache_object, weakreflist), READONLY},
14027db96d56Sopenharmony_ci    {NULL}  /* Sentinel */
14037db96d56Sopenharmony_ci};
14047db96d56Sopenharmony_ci
14057db96d56Sopenharmony_cistatic PyType_Slot lru_cache_type_slots[] = {
14067db96d56Sopenharmony_ci    {Py_tp_dealloc, lru_cache_dealloc},
14077db96d56Sopenharmony_ci    {Py_tp_call, lru_cache_call},
14087db96d56Sopenharmony_ci    {Py_tp_doc, (void *)lru_cache_doc},
14097db96d56Sopenharmony_ci    {Py_tp_traverse, lru_cache_tp_traverse},
14107db96d56Sopenharmony_ci    {Py_tp_clear, lru_cache_tp_clear},
14117db96d56Sopenharmony_ci    {Py_tp_methods, lru_cache_methods},
14127db96d56Sopenharmony_ci    {Py_tp_members, lru_cache_memberlist},
14137db96d56Sopenharmony_ci    {Py_tp_getset, lru_cache_getsetlist},
14147db96d56Sopenharmony_ci    {Py_tp_descr_get, lru_cache_descr_get},
14157db96d56Sopenharmony_ci    {Py_tp_new, lru_cache_new},
14167db96d56Sopenharmony_ci    {0, 0}
14177db96d56Sopenharmony_ci};
14187db96d56Sopenharmony_ci
14197db96d56Sopenharmony_cistatic PyType_Spec lru_cache_type_spec = {
14207db96d56Sopenharmony_ci    .name = "functools._lru_cache_wrapper",
14217db96d56Sopenharmony_ci    .basicsize = sizeof(lru_cache_object),
14227db96d56Sopenharmony_ci    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
14237db96d56Sopenharmony_ci             Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_IMMUTABLETYPE,
14247db96d56Sopenharmony_ci    .slots = lru_cache_type_slots
14257db96d56Sopenharmony_ci};
14267db96d56Sopenharmony_ci
14277db96d56Sopenharmony_ci
14287db96d56Sopenharmony_ci/* module level code ********************************************************/
14297db96d56Sopenharmony_ci
14307db96d56Sopenharmony_ciPyDoc_STRVAR(_functools_doc,
14317db96d56Sopenharmony_ci"Tools that operate on functions.");
14327db96d56Sopenharmony_ci
14337db96d56Sopenharmony_cistatic PyMethodDef _functools_methods[] = {
14347db96d56Sopenharmony_ci    {"reduce",          functools_reduce,     METH_VARARGS, functools_reduce_doc},
14357db96d56Sopenharmony_ci    {"cmp_to_key",      _PyCFunction_CAST(functools_cmp_to_key),
14367db96d56Sopenharmony_ci     METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
14377db96d56Sopenharmony_ci    {NULL,              NULL}           /* sentinel */
14387db96d56Sopenharmony_ci};
14397db96d56Sopenharmony_ci
14407db96d56Sopenharmony_cistatic int
14417db96d56Sopenharmony_ci_functools_exec(PyObject *module)
14427db96d56Sopenharmony_ci{
14437db96d56Sopenharmony_ci    _functools_state *state = get_functools_state(module);
14447db96d56Sopenharmony_ci    state->kwd_mark = _PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type);
14457db96d56Sopenharmony_ci    if (state->kwd_mark == NULL) {
14467db96d56Sopenharmony_ci        return -1;
14477db96d56Sopenharmony_ci    }
14487db96d56Sopenharmony_ci
14497db96d56Sopenharmony_ci    state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
14507db96d56Sopenharmony_ci        &partial_type_spec, NULL);
14517db96d56Sopenharmony_ci    if (state->partial_type == NULL) {
14527db96d56Sopenharmony_ci        return -1;
14537db96d56Sopenharmony_ci    }
14547db96d56Sopenharmony_ci    if (PyModule_AddType(module, state->partial_type) < 0) {
14557db96d56Sopenharmony_ci        return -1;
14567db96d56Sopenharmony_ci    }
14577db96d56Sopenharmony_ci
14587db96d56Sopenharmony_ci    PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
14597db96d56Sopenharmony_ci        &lru_cache_type_spec, NULL);
14607db96d56Sopenharmony_ci    if (lru_cache_type == NULL) {
14617db96d56Sopenharmony_ci        return -1;
14627db96d56Sopenharmony_ci    }
14637db96d56Sopenharmony_ci    if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
14647db96d56Sopenharmony_ci        Py_DECREF(lru_cache_type);
14657db96d56Sopenharmony_ci        return -1;
14667db96d56Sopenharmony_ci    }
14677db96d56Sopenharmony_ci    Py_DECREF(lru_cache_type);
14687db96d56Sopenharmony_ci
14697db96d56Sopenharmony_ci    state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
14707db96d56Sopenharmony_ci        &keyobject_type_spec, NULL);
14717db96d56Sopenharmony_ci    if (state->keyobject_type == NULL) {
14727db96d56Sopenharmony_ci        return -1;
14737db96d56Sopenharmony_ci    }
14747db96d56Sopenharmony_ci    // keyobject_type is used only internally.
14757db96d56Sopenharmony_ci    // So we don't expose it in module namespace.
14767db96d56Sopenharmony_ci
14777db96d56Sopenharmony_ci    state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
14787db96d56Sopenharmony_ci        module, &lru_list_elem_type_spec, NULL);
14797db96d56Sopenharmony_ci    if (state->lru_list_elem_type == NULL) {
14807db96d56Sopenharmony_ci        return -1;
14817db96d56Sopenharmony_ci    }
14827db96d56Sopenharmony_ci    // lru_list_elem is used only in _lru_cache_wrapper.
14837db96d56Sopenharmony_ci    // So we don't expose it in module namespace.
14847db96d56Sopenharmony_ci
14857db96d56Sopenharmony_ci    return 0;
14867db96d56Sopenharmony_ci}
14877db96d56Sopenharmony_ci
14887db96d56Sopenharmony_cistatic int
14897db96d56Sopenharmony_ci_functools_traverse(PyObject *module, visitproc visit, void *arg)
14907db96d56Sopenharmony_ci{
14917db96d56Sopenharmony_ci    _functools_state *state = get_functools_state(module);
14927db96d56Sopenharmony_ci    Py_VISIT(state->kwd_mark);
14937db96d56Sopenharmony_ci    Py_VISIT(state->partial_type);
14947db96d56Sopenharmony_ci    Py_VISIT(state->keyobject_type);
14957db96d56Sopenharmony_ci    Py_VISIT(state->lru_list_elem_type);
14967db96d56Sopenharmony_ci    return 0;
14977db96d56Sopenharmony_ci}
14987db96d56Sopenharmony_ci
14997db96d56Sopenharmony_cistatic int
15007db96d56Sopenharmony_ci_functools_clear(PyObject *module)
15017db96d56Sopenharmony_ci{
15027db96d56Sopenharmony_ci    _functools_state *state = get_functools_state(module);
15037db96d56Sopenharmony_ci    Py_CLEAR(state->kwd_mark);
15047db96d56Sopenharmony_ci    Py_CLEAR(state->partial_type);
15057db96d56Sopenharmony_ci    Py_CLEAR(state->keyobject_type);
15067db96d56Sopenharmony_ci    Py_CLEAR(state->lru_list_elem_type);
15077db96d56Sopenharmony_ci    return 0;
15087db96d56Sopenharmony_ci}
15097db96d56Sopenharmony_ci
15107db96d56Sopenharmony_cistatic void
15117db96d56Sopenharmony_ci_functools_free(void *module)
15127db96d56Sopenharmony_ci{
15137db96d56Sopenharmony_ci    _functools_clear((PyObject *)module);
15147db96d56Sopenharmony_ci}
15157db96d56Sopenharmony_ci
15167db96d56Sopenharmony_cistatic struct PyModuleDef_Slot _functools_slots[] = {
15177db96d56Sopenharmony_ci    {Py_mod_exec, _functools_exec},
15187db96d56Sopenharmony_ci    {0, NULL}
15197db96d56Sopenharmony_ci};
15207db96d56Sopenharmony_ci
15217db96d56Sopenharmony_cistatic struct PyModuleDef _functools_module = {
15227db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
15237db96d56Sopenharmony_ci    .m_name = "_functools",
15247db96d56Sopenharmony_ci    .m_doc = _functools_doc,
15257db96d56Sopenharmony_ci    .m_size = sizeof(_functools_state),
15267db96d56Sopenharmony_ci    .m_methods = _functools_methods,
15277db96d56Sopenharmony_ci    .m_slots = _functools_slots,
15287db96d56Sopenharmony_ci    .m_traverse = _functools_traverse,
15297db96d56Sopenharmony_ci    .m_clear = _functools_clear,
15307db96d56Sopenharmony_ci    .m_free = _functools_free,
15317db96d56Sopenharmony_ci};
15327db96d56Sopenharmony_ci
15337db96d56Sopenharmony_ciPyMODINIT_FUNC
15347db96d56Sopenharmony_ciPyInit__functools(void)
15357db96d56Sopenharmony_ci{
15367db96d56Sopenharmony_ci    return PyModuleDef_Init(&_functools_module);
15377db96d56Sopenharmony_ci}
1538