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