LCOV - code coverage report
Current view: top level - Modules - _functoolsmodule.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 553 647 85.5 %
Date: 2022-07-20 13:12:14 Functions: 45 46 97.8 %
Branches: 289 392 73.7 %

           Branch data     Line data    Source code
       1                 :            : #include "Python.h"
       2                 :            : #include "pycore_call.h"          // _PyObject_CallNoArgs()
       3                 :            : #include "pycore_long.h"          // _PyLong_GetZero()
       4                 :            : #include "pycore_moduleobject.h"  // _PyModule_GetState()
       5                 :            : #include "pycore_object.h"        // _PyObject_GC_TRACK
       6                 :            : #include "pycore_pystate.h"       // _PyThreadState_GET()
       7                 :            : #include "pycore_tuple.h"         // _PyTuple_ITEMS()
       8                 :            : #include "structmember.h"         // PyMemberDef
       9                 :            : 
      10                 :            : /* _functools module written and maintained
      11                 :            :    by Hye-Shik Chang <perky@FreeBSD.org>
      12                 :            :    with adaptations by Raymond Hettinger <python@rcn.com>
      13                 :            :    Copyright (c) 2004, 2005, 2006 Python Software Foundation.
      14                 :            :    All rights reserved.
      15                 :            : */
      16                 :            : 
      17                 :            : typedef struct _functools_state {
      18                 :            :     /* this object is used delimit args and keywords in the cache keys */
      19                 :            :     PyObject *kwd_mark;
      20                 :            :     PyTypeObject *partial_type;
      21                 :            :     PyTypeObject *keyobject_type;
      22                 :            :     PyTypeObject *lru_list_elem_type;
      23                 :            : } _functools_state;
      24                 :            : 
      25                 :            : static inline _functools_state *
      26                 :      72402 : get_functools_state(PyObject *module)
      27                 :            : {
      28                 :      72402 :     void *state = _PyModule_GetState(module);
      29                 :            :     assert(state != NULL);
      30                 :      72402 :     return (_functools_state *)state;
      31                 :            : }
      32                 :            : 
      33                 :            : 
      34                 :            : /* partial object **********************************************************/
      35                 :            : 
      36                 :            : typedef struct {
      37                 :            :     PyObject_HEAD
      38                 :            :     PyObject *fn;
      39                 :            :     PyObject *args;
      40                 :            :     PyObject *kw;
      41                 :            :     PyObject *dict;        /* __dict__ */
      42                 :            :     PyObject *weakreflist; /* List of weak references */
      43                 :            :     vectorcallfunc vectorcall;
      44                 :            : } partialobject;
      45                 :            : 
      46                 :            : static void partial_setvectorcall(partialobject *pto);
      47                 :            : static struct PyModuleDef _functools_module;
      48                 :            : static PyObject *
      49                 :            : partial_call(partialobject *pto, PyObject *args, PyObject *kwargs);
      50                 :            : 
      51                 :            : static inline _functools_state *
      52                 :      14963 : get_functools_state_by_type(PyTypeObject *type)
      53                 :            : {
      54                 :      14963 :     PyObject *module = PyType_GetModuleByDef(type, &_functools_module);
      55         [ -  + ]:      14963 :     if (module == NULL) {
      56                 :          0 :         return NULL;
      57                 :            :     }
      58                 :      14963 :     return get_functools_state(module);
      59                 :            : }
      60                 :            : 
      61                 :            : static PyObject *
      62                 :      76511 : partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
      63                 :            : {
      64                 :            :     PyObject *func, *pargs, *nargs, *pkw;
      65                 :            :     partialobject *pto;
      66                 :            : 
      67         [ +  + ]:      76511 :     if (PyTuple_GET_SIZE(args) < 1) {
      68                 :          2 :         PyErr_SetString(PyExc_TypeError,
      69                 :            :                         "type 'partial' takes at least one argument");
      70                 :          2 :         return NULL;
      71                 :            :     }
      72                 :            : 
      73                 :      76509 :     pargs = pkw = NULL;
      74                 :      76509 :     func = PyTuple_GET_ITEM(args, 0);
      75         [ +  + ]:      76509 :     if (Py_TYPE(func)->tp_call == (ternaryfunc)partial_call) {
      76                 :            :         // The type of "func" might not be exactly the same type object
      77                 :            :         // as "type", but if it is called using partial_call, it must have the
      78                 :            :         // same memory layout (fn, args and kw members).
      79                 :            :         // We can use its underlying function directly and merge the arguments.
      80                 :         15 :         partialobject *part = (partialobject *)func;
      81         [ +  - ]:         15 :         if (part->dict == NULL) {
      82                 :         15 :             pargs = part->args;
      83                 :         15 :             pkw = part->kw;
      84                 :         15 :             func = part->fn;
      85                 :            :             assert(PyTuple_Check(pargs));
      86                 :            :             assert(PyDict_Check(pkw));
      87                 :            :         }
      88                 :            :     }
      89         [ +  + ]:      76509 :     if (!PyCallable_Check(func)) {
      90                 :          2 :         PyErr_SetString(PyExc_TypeError,
      91                 :            :                         "the first argument must be callable");
      92                 :          2 :         return NULL;
      93                 :            :     }
      94                 :            : 
      95                 :            :     /* create partialobject structure */
      96                 :      76507 :     pto = (partialobject *)type->tp_alloc(type, 0);
      97         [ -  + ]:      76507 :     if (pto == NULL)
      98                 :          0 :         return NULL;
      99                 :            : 
     100                 :      76507 :     pto->fn = func;
     101                 :      76507 :     Py_INCREF(func);
     102                 :            : 
     103                 :      76507 :     nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
     104         [ -  + ]:      76507 :     if (nargs == NULL) {
     105                 :          0 :         Py_DECREF(pto);
     106                 :          0 :         return NULL;
     107                 :            :     }
     108         [ +  + ]:      76507 :     if (pargs == NULL) {
     109                 :      76492 :         pto->args = nargs;
     110                 :            :     }
     111                 :            :     else {
     112                 :         15 :         pto->args = PySequence_Concat(pargs, nargs);
     113                 :         15 :         Py_DECREF(nargs);
     114         [ -  + ]:         15 :         if (pto->args == NULL) {
     115                 :          0 :             Py_DECREF(pto);
     116                 :          0 :             return NULL;
     117                 :            :         }
     118                 :            :         assert(PyTuple_Check(pto->args));
     119                 :            :     }
     120                 :            : 
     121   [ +  +  +  + ]:      76507 :     if (pkw == NULL || PyDict_GET_SIZE(pkw) == 0) {
     122         [ +  + ]:      76503 :         if (kw == NULL) {
     123                 :       4537 :             pto->kw = PyDict_New();
     124                 :            :         }
     125         [ +  + ]:      71966 :         else if (Py_REFCNT(kw) == 1) {
     126                 :      71958 :             Py_INCREF(kw);
     127                 :      71958 :             pto->kw = kw;
     128                 :            :         }
     129                 :            :         else {
     130                 :          8 :             pto->kw = PyDict_Copy(kw);
     131                 :            :         }
     132                 :            :     }
     133                 :            :     else {
     134                 :          4 :         pto->kw = PyDict_Copy(pkw);
     135   [ +  -  +  - ]:          4 :         if (kw != NULL && pto->kw != NULL) {
     136         [ -  + ]:          4 :             if (PyDict_Merge(pto->kw, kw, 1) != 0) {
     137                 :          0 :                 Py_DECREF(pto);
     138                 :          0 :                 return NULL;
     139                 :            :             }
     140                 :            :         }
     141                 :            :     }
     142         [ -  + ]:      76507 :     if (pto->kw == NULL) {
     143                 :          0 :         Py_DECREF(pto);
     144                 :          0 :         return NULL;
     145                 :            :     }
     146                 :            : 
     147                 :      76507 :     partial_setvectorcall(pto);
     148                 :      76507 :     return (PyObject *)pto;
     149                 :            : }
     150                 :            : 
     151                 :            : static int
     152                 :      76561 : partial_clear(partialobject *pto)
     153                 :            : {
     154         [ +  + ]:      76561 :     Py_CLEAR(pto->fn);
     155         [ +  + ]:      76561 :     Py_CLEAR(pto->args);
     156         [ +  + ]:      76561 :     Py_CLEAR(pto->kw);
     157         [ +  + ]:      76561 :     Py_CLEAR(pto->dict);
     158                 :      76561 :     return 0;
     159                 :            : }
     160                 :            : 
     161                 :            : static int
     162                 :     608590 : partial_traverse(partialobject *pto, visitproc visit, void *arg)
     163                 :            : {
     164   [ +  -  -  + ]:     608590 :     Py_VISIT(Py_TYPE(pto));
     165   [ +  -  -  + ]:     608590 :     Py_VISIT(pto->fn);
     166   [ +  -  -  + ]:     608590 :     Py_VISIT(pto->args);
     167   [ +  -  -  + ]:     608590 :     Py_VISIT(pto->kw);
     168   [ +  +  -  + ]:     608590 :     Py_VISIT(pto->dict);
     169                 :     608590 :     return 0;
     170                 :            : }
     171                 :            : 
     172                 :            : static void
     173                 :      76489 : partial_dealloc(partialobject *pto)
     174                 :            : {
     175                 :      76489 :     PyTypeObject *tp = Py_TYPE(pto);
     176                 :            :     /* bpo-31095: UnTrack is needed before calling any callbacks */
     177                 :      76489 :     PyObject_GC_UnTrack(pto);
     178         [ +  + ]:      76489 :     if (pto->weakreflist != NULL) {
     179                 :          2 :         PyObject_ClearWeakRefs((PyObject *) pto);
     180                 :            :     }
     181                 :      76489 :     (void)partial_clear(pto);
     182                 :      76489 :     tp->tp_free(pto);
     183                 :      76489 :     Py_DECREF(tp);
     184                 :      76489 : }
     185                 :            : 
     186                 :            : 
     187                 :            : /* Merging keyword arguments using the vectorcall convention is messy, so
     188                 :            :  * if we would need to do that, we stop using vectorcall and fall back
     189                 :            :  * to using partial_call() instead. */
     190                 :            : Py_NO_INLINE static PyObject *
     191                 :      50469 : partial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto,
     192                 :            :                             PyObject *const *args, size_t nargsf,
     193                 :            :                             PyObject *kwnames)
     194                 :            : {
     195                 :      50469 :     pto->vectorcall = NULL;
     196                 :      50469 :     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
     197                 :      50469 :     return _PyObject_MakeTpCall(tstate, (PyObject *)pto,
     198                 :            :                                 args, nargs, kwnames);
     199                 :            : }
     200                 :            : 
     201                 :            : static PyObject *
     202                 :      53733 : partial_vectorcall(partialobject *pto, PyObject *const *args,
     203                 :            :                    size_t nargsf, PyObject *kwnames)
     204                 :            : {
     205                 :      53733 :     PyThreadState *tstate = _PyThreadState_GET();
     206                 :            : 
     207                 :            :     /* pto->kw is mutable, so need to check every time */
     208         [ +  + ]:      53733 :     if (PyDict_GET_SIZE(pto->kw)) {
     209                 :      50469 :         return partial_vectorcall_fallback(tstate, pto, args, nargsf, kwnames);
     210                 :            :     }
     211                 :            : 
     212                 :       3264 :     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
     213                 :       3264 :     Py_ssize_t nargs_total = nargs;
     214         [ +  + ]:       3264 :     if (kwnames != NULL) {
     215                 :         52 :         nargs_total += PyTuple_GET_SIZE(kwnames);
     216                 :            :     }
     217                 :            : 
     218                 :       3264 :     PyObject **pto_args = _PyTuple_ITEMS(pto->args);
     219                 :       3264 :     Py_ssize_t pto_nargs = PyTuple_GET_SIZE(pto->args);
     220                 :            : 
     221                 :            :     /* Fast path if we're called without arguments */
     222         [ +  + ]:       3264 :     if (nargs_total == 0) {
     223                 :       2685 :         return _PyObject_VectorcallTstate(tstate, pto->fn,
     224                 :            :                                           pto_args, pto_nargs, NULL);
     225                 :            :     }
     226                 :            : 
     227                 :            :     /* Fast path using PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
     228                 :            :      * positional argument */
     229   [ +  +  +  + ]:        579 :     if (pto_nargs == 1 && (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET)) {
     230                 :        362 :         PyObject **newargs = (PyObject **)args - 1;
     231                 :        362 :         PyObject *tmp = newargs[0];
     232                 :        362 :         newargs[0] = pto_args[0];
     233                 :        362 :         PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn,
     234                 :        362 :                                                    newargs, nargs + 1, kwnames);
     235                 :        362 :         newargs[0] = tmp;
     236                 :        362 :         return ret;
     237                 :            :     }
     238                 :            : 
     239                 :        217 :     Py_ssize_t newnargs_total = pto_nargs + nargs_total;
     240                 :            : 
     241                 :            :     PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
     242                 :            :     PyObject *ret;
     243                 :            :     PyObject **stack;
     244                 :            : 
     245         [ +  - ]:        217 :     if (newnargs_total <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
     246                 :        217 :         stack = small_stack;
     247                 :            :     }
     248                 :            :     else {
     249                 :          0 :         stack = PyMem_Malloc(newnargs_total * sizeof(PyObject *));
     250         [ #  # ]:          0 :         if (stack == NULL) {
     251                 :            :             PyErr_NoMemory();
     252                 :          0 :             return NULL;
     253                 :            :         }
     254                 :            :     }
     255                 :            : 
     256                 :            :     /* Copy to new stack, using borrowed references */
     257                 :        217 :     memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
     258                 :        217 :     memcpy(stack + pto_nargs, args, nargs_total * sizeof(PyObject*));
     259                 :            : 
     260                 :        217 :     ret = _PyObject_VectorcallTstate(tstate, pto->fn,
     261                 :        217 :                                      stack, pto_nargs + nargs, kwnames);
     262         [ -  + ]:        217 :     if (stack != small_stack) {
     263                 :          0 :         PyMem_Free(stack);
     264                 :            :     }
     265                 :        217 :     return ret;
     266                 :            : }
     267                 :            : 
     268                 :            : /* Set pto->vectorcall depending on the parameters of the partial object */
     269                 :            : static void
     270                 :      76719 : partial_setvectorcall(partialobject *pto)
     271                 :            : {
     272         [ +  + ]:      76719 :     if (_PyVectorcall_Function(pto->fn) == NULL) {
     273                 :            :         /* Don't use vectorcall if the underlying function doesn't support it */
     274                 :       2896 :         pto->vectorcall = NULL;
     275                 :            :     }
     276                 :            :     /* We could have a special case if there are no arguments,
     277                 :            :      * but that is unlikely (why use partial without arguments?),
     278                 :            :      * so we don't optimize that */
     279                 :            :     else {
     280                 :      73823 :         pto->vectorcall = (vectorcallfunc)partial_vectorcall;
     281                 :            :     }
     282                 :      76719 : }
     283                 :            : 
     284                 :            : 
     285                 :            : static PyObject *
     286                 :      53644 : partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
     287                 :            : {
     288                 :            :     assert(PyCallable_Check(pto->fn));
     289                 :            :     assert(PyTuple_Check(pto->args));
     290                 :            :     assert(PyDict_Check(pto->kw));
     291                 :            : 
     292                 :            :     /* Merge keywords */
     293                 :            :     PyObject *kwargs2;
     294         [ +  + ]:      53644 :     if (PyDict_GET_SIZE(pto->kw) == 0) {
     295                 :            :         /* kwargs can be NULL */
     296                 :         93 :         kwargs2 = kwargs;
     297                 :         93 :         Py_XINCREF(kwargs2);
     298                 :            :     }
     299                 :            :     else {
     300                 :            :         /* bpo-27840, bpo-29318: dictionary of keyword parameters must be
     301                 :            :            copied, because a function using "**kwargs" can modify the
     302                 :            :            dictionary. */
     303                 :      53551 :         kwargs2 = PyDict_Copy(pto->kw);
     304         [ -  + ]:      53551 :         if (kwargs2 == NULL) {
     305                 :          0 :             return NULL;
     306                 :            :         }
     307                 :            : 
     308         [ +  + ]:      53551 :         if (kwargs != NULL) {
     309         [ -  + ]:        328 :             if (PyDict_Merge(kwargs2, kwargs, 1) != 0) {
     310                 :          0 :                 Py_DECREF(kwargs2);
     311                 :          0 :                 return NULL;
     312                 :            :             }
     313                 :            :         }
     314                 :            :     }
     315                 :            : 
     316                 :            :     /* Merge positional arguments */
     317                 :            :     /* Note: tupleconcat() is optimized for empty tuples */
     318                 :      53644 :     PyObject *args2 = PySequence_Concat(pto->args, args);
     319         [ -  + ]:      53644 :     if (args2 == NULL) {
     320                 :          0 :         Py_XDECREF(kwargs2);
     321                 :          0 :         return NULL;
     322                 :            :     }
     323                 :            : 
     324                 :      53644 :     PyObject *res = PyObject_Call(pto->fn, args2, kwargs2);
     325                 :      53644 :     Py_DECREF(args2);
     326                 :      53644 :     Py_XDECREF(kwargs2);
     327                 :      53644 :     return res;
     328                 :            : }
     329                 :            : 
     330                 :            : PyDoc_STRVAR(partial_doc,
     331                 :            : "partial(func, *args, **keywords) - new function with partial application\n\
     332                 :            :     of the given arguments and keywords.\n");
     333                 :            : 
     334                 :            : #define OFF(x) offsetof(partialobject, x)
     335                 :            : static PyMemberDef partial_memberlist[] = {
     336                 :            :     {"func",            T_OBJECT,       OFF(fn),        READONLY,
     337                 :            :      "function object to use in future partial calls"},
     338                 :            :     {"args",            T_OBJECT,       OFF(args),      READONLY,
     339                 :            :      "tuple of arguments to future partial calls"},
     340                 :            :     {"keywords",        T_OBJECT,       OFF(kw),        READONLY,
     341                 :            :      "dictionary of keyword arguments to future partial calls"},
     342                 :            :     {"__weaklistoffset__", T_PYSSIZET,
     343                 :            :      offsetof(partialobject, weakreflist), READONLY},
     344                 :            :     {"__dictoffset__", T_PYSSIZET,
     345                 :            :      offsetof(partialobject, dict), READONLY},
     346                 :            :     {"__vectorcalloffset__", T_PYSSIZET,
     347                 :            :      offsetof(partialobject, vectorcall), READONLY},
     348                 :            :     {NULL}  /* Sentinel */
     349                 :            : };
     350                 :            : 
     351                 :            : static PyGetSetDef partial_getsetlist[] = {
     352                 :            :     {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
     353                 :            :     {NULL} /* Sentinel */
     354                 :            : };
     355                 :            : 
     356                 :            : static PyObject *
     357                 :       1718 : partial_repr(partialobject *pto)
     358                 :            : {
     359                 :       1718 :     PyObject *result = NULL;
     360                 :            :     PyObject *arglist;
     361                 :            :     Py_ssize_t i, n;
     362                 :            :     PyObject *key, *value;
     363                 :            :     int status;
     364                 :            : 
     365                 :       1718 :     status = Py_ReprEnter((PyObject *)pto);
     366         [ +  + ]:       1718 :     if (status != 0) {
     367         [ -  + ]:          6 :         if (status < 0)
     368                 :          0 :             return NULL;
     369                 :          6 :         return PyUnicode_FromString("...");
     370                 :            :     }
     371                 :            : 
     372                 :       1712 :     arglist = PyUnicode_FromString("");
     373         [ -  + ]:       1712 :     if (arglist == NULL)
     374                 :          0 :         goto done;
     375                 :            :     /* Pack positional arguments */
     376                 :            :     assert (PyTuple_Check(pto->args));
     377                 :       1712 :     n = PyTuple_GET_SIZE(pto->args);
     378         [ +  + ]:       1729 :     for (i = 0; i < n; i++) {
     379                 :         17 :         Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
     380                 :            :                                         PyTuple_GET_ITEM(pto->args, i)));
     381         [ -  + ]:         17 :         if (arglist == NULL)
     382                 :          0 :             goto done;
     383                 :            :     }
     384                 :            :     /* Pack keyword arguments */
     385                 :            :     assert (PyDict_Check(pto->kw));
     386         [ +  + ]:       3413 :     for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
     387                 :            :         /* Prevent key.__str__ from deleting the value. */
     388                 :       1701 :         Py_INCREF(value);
     389                 :       1701 :         Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
     390                 :            :                                                 key, value));
     391                 :       1701 :         Py_DECREF(value);
     392         [ -  + ]:       1701 :         if (arglist == NULL)
     393                 :          0 :             goto done;
     394                 :            :     }
     395                 :       1712 :     result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
     396                 :            :                                   pto->fn, arglist);
     397                 :       1712 :     Py_DECREF(arglist);
     398                 :            : 
     399                 :       1712 :  done:
     400                 :       1712 :     Py_ReprLeave((PyObject *)pto);
     401                 :       1712 :     return result;
     402                 :            : }
     403                 :            : 
     404                 :            : /* Pickle strategy:
     405                 :            :    __reduce__ by itself doesn't support getting kwargs in the unpickle
     406                 :            :    operation so we define a __setstate__ that replaces all the information
     407                 :            :    about the partial.  If we only replaced part of it someone would use
     408                 :            :    it as a hook to do strange things.
     409                 :            :  */
     410                 :            : 
     411                 :            : static PyObject *
     412                 :       5972 : partial_reduce(partialobject *pto, PyObject *unused)
     413                 :            : {
     414                 :       5972 :     return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
     415                 :            :                          pto->args, pto->kw,
     416         [ +  + ]:       5972 :                          pto->dict ? pto->dict : Py_None);
     417                 :            : }
     418                 :            : 
     419                 :            : static PyObject *
     420                 :        228 : partial_setstate(partialobject *pto, PyObject *state)
     421                 :            : {
     422                 :            :     PyObject *fn, *fnargs, *kw, *dict;
     423                 :            : 
     424   [ +  +  +  + ]:        452 :     if (!PyTuple_Check(state) ||
     425         [ +  + ]:        444 :         !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
     426         [ +  + ]:        438 :         !PyCallable_Check(fn) ||
     427                 :        218 :         !PyTuple_Check(fnargs) ||
     428   [ +  +  +  + ]:        214 :         (kw != Py_None && !PyDict_Check(kw)))
     429                 :            :     {
     430                 :         16 :         PyErr_SetString(PyExc_TypeError, "invalid partial state");
     431                 :         16 :         return NULL;
     432                 :            :     }
     433                 :            : 
     434         [ +  + ]:        212 :     if(!PyTuple_CheckExact(fnargs))
     435                 :          4 :         fnargs = PySequence_Tuple(fnargs);
     436                 :            :     else
     437                 :        208 :         Py_INCREF(fnargs);
     438         [ -  + ]:        212 :     if (fnargs == NULL)
     439                 :          0 :         return NULL;
     440                 :            : 
     441         [ +  + ]:        212 :     if (kw == Py_None)
     442                 :          2 :         kw = PyDict_New();
     443         [ +  + ]:        210 :     else if(!PyDict_CheckExact(kw))
     444                 :          2 :         kw = PyDict_Copy(kw);
     445                 :            :     else
     446                 :        208 :         Py_INCREF(kw);
     447         [ -  + ]:        212 :     if (kw == NULL) {
     448                 :          0 :         Py_DECREF(fnargs);
     449                 :          0 :         return NULL;
     450                 :            :     }
     451                 :            : 
     452         [ +  + ]:        212 :     if (dict == Py_None)
     453                 :        122 :         dict = NULL;
     454                 :            :     else
     455                 :         90 :         Py_INCREF(dict);
     456                 :            : 
     457                 :        212 :     Py_INCREF(fn);
     458                 :        212 :     Py_SETREF(pto->fn, fn);
     459                 :        212 :     Py_SETREF(pto->args, fnargs);
     460                 :        212 :     Py_SETREF(pto->kw, kw);
     461                 :        212 :     Py_XSETREF(pto->dict, dict);
     462                 :        212 :     partial_setvectorcall(pto);
     463                 :        212 :     Py_RETURN_NONE;
     464                 :            : }
     465                 :            : 
     466                 :            : static PyMethodDef partial_methods[] = {
     467                 :            :     {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
     468                 :            :     {"__setstate__", (PyCFunction)partial_setstate, METH_O},
     469                 :            :     {"__class_getitem__",    Py_GenericAlias,
     470                 :            :     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")},
     471                 :            :     {NULL,              NULL}           /* sentinel */
     472                 :            : };
     473                 :            : 
     474                 :            : static PyType_Slot partial_type_slots[] = {
     475                 :            :     {Py_tp_dealloc, partial_dealloc},
     476                 :            :     {Py_tp_repr, partial_repr},
     477                 :            :     {Py_tp_call, partial_call},
     478                 :            :     {Py_tp_getattro, PyObject_GenericGetAttr},
     479                 :            :     {Py_tp_setattro, PyObject_GenericSetAttr},
     480                 :            :     {Py_tp_doc, (void *)partial_doc},
     481                 :            :     {Py_tp_traverse, partial_traverse},
     482                 :            :     {Py_tp_clear, partial_clear},
     483                 :            :     {Py_tp_methods, partial_methods},
     484                 :            :     {Py_tp_members, partial_memberlist},
     485                 :            :     {Py_tp_getset, partial_getsetlist},
     486                 :            :     {Py_tp_new, partial_new},
     487                 :            :     {Py_tp_free, PyObject_GC_Del},
     488                 :            :     {0, 0}
     489                 :            : };
     490                 :            : 
     491                 :            : static PyType_Spec partial_type_spec = {
     492                 :            :     .name = "functools.partial",
     493                 :            :     .basicsize = sizeof(partialobject),
     494                 :            :     .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
     495                 :            :              Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL |
     496                 :            :              Py_TPFLAGS_IMMUTABLETYPE,
     497                 :            :     .slots = partial_type_slots
     498                 :            : };
     499                 :            : 
     500                 :            : 
     501                 :            : /* cmp_to_key ***************************************************************/
     502                 :            : 
     503                 :            : typedef struct {
     504                 :            :     PyObject_HEAD
     505                 :            :     PyObject *cmp;
     506                 :            :     PyObject *object;
     507                 :            : } keyobject;
     508                 :            : 
     509                 :            : static int
     510                 :      63907 : keyobject_clear(keyobject *ko)
     511                 :            : {
     512         [ +  - ]:      63907 :     Py_CLEAR(ko->cmp);
     513         [ +  + ]:      63907 :     Py_CLEAR(ko->object);
     514                 :      63907 :     return 0;
     515                 :            : }
     516                 :            : 
     517                 :            : static void
     518                 :      63907 : keyobject_dealloc(keyobject *ko)
     519                 :            : {
     520                 :      63907 :     PyTypeObject *tp = Py_TYPE(ko);
     521                 :      63907 :     PyObject_GC_UnTrack(ko);
     522                 :      63907 :     (void)keyobject_clear(ko);
     523                 :      63907 :     tp->tp_free(ko);
     524                 :      63907 :     Py_DECREF(tp);
     525                 :      63907 : }
     526                 :            : 
     527                 :            : static int
     528                 :       5354 : keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
     529                 :            : {
     530   [ +  -  -  + ]:       5354 :     Py_VISIT(Py_TYPE(ko));
     531   [ +  -  -  + ]:       5354 :     Py_VISIT(ko->cmp);
     532   [ +  +  -  + ]:       5354 :     Py_VISIT(ko->object);
     533                 :       5354 :     return 0;
     534                 :            : }
     535                 :            : 
     536                 :            : static PyMemberDef keyobject_members[] = {
     537                 :            :     {"obj", T_OBJECT,
     538                 :            :      offsetof(keyobject, object), 0,
     539                 :            :      PyDoc_STR("Value wrapped by a key function.")},
     540                 :            :     {NULL}
     541                 :            : };
     542                 :            : 
     543                 :            : static PyObject *
     544                 :            : keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
     545                 :            : 
     546                 :            : static PyObject *
     547                 :            : keyobject_richcompare(PyObject *ko, PyObject *other, int op);
     548                 :            : 
     549                 :            : static PyType_Slot keyobject_type_slots[] = {
     550                 :            :     {Py_tp_dealloc, keyobject_dealloc},
     551                 :            :     {Py_tp_call, keyobject_call},
     552                 :            :     {Py_tp_getattro, PyObject_GenericGetAttr},
     553                 :            :     {Py_tp_traverse, keyobject_traverse},
     554                 :            :     {Py_tp_clear, keyobject_clear},
     555                 :            :     {Py_tp_richcompare, keyobject_richcompare},
     556                 :            :     {Py_tp_members, keyobject_members},
     557                 :            :     {0, 0}
     558                 :            : };
     559                 :            : 
     560                 :            : static PyType_Spec keyobject_type_spec = {
     561                 :            :     .name = "functools.KeyWrapper",
     562                 :            :     .basicsize = sizeof(keyobject),
     563                 :            :     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
     564                 :            :               Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
     565                 :            :     .slots = keyobject_type_slots
     566                 :            : };
     567                 :            : 
     568                 :            : static PyObject *
     569                 :      59536 : keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
     570                 :            : {
     571                 :            :     PyObject *object;
     572                 :            :     keyobject *result;
     573                 :            :     static char *kwargs[] = {"obj", NULL};
     574                 :            : 
     575         [ +  + ]:      59536 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
     576                 :          2 :         return NULL;
     577                 :            : 
     578                 :      59534 :     result = PyObject_GC_New(keyobject, Py_TYPE(ko));
     579         [ -  + ]:      59534 :     if (result == NULL) {
     580                 :          0 :         return NULL;
     581                 :            :     }
     582                 :      59534 :     Py_INCREF(ko->cmp);
     583                 :      59534 :     result->cmp = ko->cmp;
     584                 :      59534 :     Py_INCREF(object);
     585                 :      59534 :     result->object = object;
     586                 :      59534 :     PyObject_GC_Track(result);
     587                 :      59534 :     return (PyObject *)result;
     588                 :            : }
     589                 :            : 
     590                 :            : static PyObject *
     591                 :     127897 : keyobject_richcompare(PyObject *ko, PyObject *other, int op)
     592                 :            : {
     593                 :            :     PyObject *res;
     594                 :            :     PyObject *x;
     595                 :            :     PyObject *y;
     596                 :            :     PyObject *compare;
     597                 :            :     PyObject *answer;
     598                 :            :     PyObject* stack[2];
     599                 :            : 
     600         [ +  + ]:     127897 :     if (!Py_IS_TYPE(other, Py_TYPE(ko))) {
     601                 :          2 :         PyErr_Format(PyExc_TypeError, "other argument must be K instance");
     602                 :          2 :         return NULL;
     603                 :            :     }
     604                 :     127895 :     compare = ((keyobject *) ko)->cmp;
     605                 :            :     assert(compare != NULL);
     606                 :     127895 :     x = ((keyobject *) ko)->object;
     607                 :     127895 :     y = ((keyobject *) other)->object;
     608   [ +  -  -  + ]:     127895 :     if (!x || !y){
     609                 :          0 :         PyErr_Format(PyExc_AttributeError, "object");
     610                 :          0 :         return NULL;
     611                 :            :     }
     612                 :            : 
     613                 :            :     /* Call the user's comparison function and translate the 3-way
     614                 :            :      * result into true or false (or error).
     615                 :            :      */
     616                 :     127895 :     stack[0] = x;
     617                 :     127895 :     stack[1] = y;
     618                 :     127895 :     res = _PyObject_FastCall(compare, stack, 2);
     619         [ +  + ]:     127895 :     if (res == NULL) {
     620                 :          2 :         return NULL;
     621                 :            :     }
     622                 :            : 
     623                 :     127893 :     answer = PyObject_RichCompare(res, _PyLong_GetZero(), op);
     624                 :     127893 :     Py_DECREF(res);
     625                 :     127893 :     return answer;
     626                 :            : }
     627                 :            : 
     628                 :            : static PyObject *
     629                 :       4375 : functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
     630                 :            : {
     631                 :            :     PyObject *cmp;
     632                 :            :     static char *kwargs[] = {"mycmp", NULL};
     633                 :            :     keyobject *object;
     634                 :            :     _functools_state *state;
     635                 :            : 
     636         [ +  + ]:       4375 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
     637                 :          2 :         return NULL;
     638                 :            : 
     639                 :       4373 :     state = get_functools_state(self);
     640                 :       4373 :     object = PyObject_GC_New(keyobject, state->keyobject_type);
     641         [ -  + ]:       4373 :     if (!object)
     642                 :          0 :         return NULL;
     643                 :       4373 :     Py_INCREF(cmp);
     644                 :       4373 :     object->cmp = cmp;
     645                 :       4373 :     object->object = NULL;
     646                 :       4373 :     PyObject_GC_Track(object);
     647                 :       4373 :     return (PyObject *)object;
     648                 :            : }
     649                 :            : 
     650                 :            : PyDoc_STRVAR(functools_cmp_to_key_doc,
     651                 :            : "Convert a cmp= function into a key= function.");
     652                 :            : 
     653                 :            : /* reduce (used to be a builtin) ********************************************/
     654                 :            : 
     655                 :            : static PyObject *
     656                 :       1104 : functools_reduce(PyObject *self, PyObject *args)
     657                 :            : {
     658                 :       1104 :     PyObject *seq, *func, *result = NULL, *it;
     659                 :            : 
     660         [ +  + ]:       1104 :     if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
     661                 :          1 :         return NULL;
     662         [ +  + ]:       1103 :     if (result != NULL)
     663                 :       1073 :         Py_INCREF(result);
     664                 :            : 
     665                 :       1103 :     it = PyObject_GetIter(seq);
     666         [ +  + ]:       1103 :     if (it == NULL) {
     667         [ +  + ]:          4 :         if (PyErr_ExceptionMatches(PyExc_TypeError))
     668                 :          3 :             PyErr_SetString(PyExc_TypeError,
     669                 :            :                             "reduce() arg 2 must support iteration");
     670                 :          4 :         Py_XDECREF(result);
     671                 :          4 :         return NULL;
     672                 :            :     }
     673                 :            : 
     674         [ +  - ]:       1099 :     if ((args = PyTuple_New(2)) == NULL)
     675                 :          0 :         goto Fail;
     676                 :            : 
     677                 :       2253 :     for (;;) {
     678                 :            :         PyObject *op2;
     679                 :            : 
     680         [ -  + ]:       3352 :         if (Py_REFCNT(args) > 1) {
     681                 :          0 :             Py_DECREF(args);
     682         [ #  # ]:          0 :             if ((args = PyTuple_New(2)) == NULL)
     683                 :          0 :                 goto Fail;
     684                 :            :         }
     685                 :            : 
     686                 :       3352 :         op2 = PyIter_Next(it);
     687         [ +  + ]:       3352 :         if (op2 == NULL) {
     688         [ +  + ]:       1097 :             if (PyErr_Occurred())
     689                 :          1 :                 goto Fail;
     690                 :       1096 :             break;
     691                 :            :         }
     692                 :            : 
     693         [ +  + ]:       2255 :         if (result == NULL)
     694                 :         22 :             result = op2;
     695                 :            :         else {
     696                 :            :             /* Update the args tuple in-place */
     697                 :            :             assert(Py_REFCNT(args) == 1);
     698                 :       2233 :             Py_XSETREF(_PyTuple_ITEMS(args)[0], result);
     699                 :       2233 :             Py_XSETREF(_PyTuple_ITEMS(args)[1], op2);
     700         [ +  + ]:       2233 :             if ((result = PyObject_Call(func, args, NULL)) == NULL) {
     701                 :          2 :                 goto Fail;
     702                 :            :             }
     703                 :            :             // bpo-42536: The GC may have untracked this args tuple. Since we're
     704                 :            :             // recycling it, make sure it's tracked again:
     705         [ -  + ]:       2231 :             if (!_PyObject_GC_IS_TRACKED(args)) {
     706                 :          0 :                 _PyObject_GC_TRACK(args);
     707                 :            :             }
     708                 :            :         }
     709                 :            :     }
     710                 :            : 
     711                 :       1096 :     Py_DECREF(args);
     712                 :            : 
     713         [ +  + ]:       1096 :     if (result == NULL)
     714                 :          4 :         PyErr_SetString(PyExc_TypeError,
     715                 :            :                    "reduce() of empty iterable with no initial value");
     716                 :            : 
     717                 :       1096 :     Py_DECREF(it);
     718                 :       1096 :     return result;
     719                 :            : 
     720                 :          3 : Fail:
     721                 :          3 :     Py_XDECREF(args);
     722                 :          3 :     Py_XDECREF(result);
     723                 :          3 :     Py_DECREF(it);
     724                 :          3 :     return NULL;
     725                 :            : }
     726                 :            : 
     727                 :            : PyDoc_STRVAR(functools_reduce_doc,
     728                 :            : "reduce(function, iterable[, initial]) -> value\n\
     729                 :            : \n\
     730                 :            : Apply a function of two arguments cumulatively to the items of a sequence\n\
     731                 :            : or iterable, from left to right, so as to reduce the iterable to a single\n\
     732                 :            : value.  For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
     733                 :            : ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items\n\
     734                 :            : of the iterable in the calculation, and serves as a default when the\n\
     735                 :            : iterable is empty.");
     736                 :            : 
     737                 :            : /* lru_cache object **********************************************************/
     738                 :            : 
     739                 :            : /* There are four principal algorithmic differences from the pure python version:
     740                 :            : 
     741                 :            :    1). The C version relies on the GIL instead of having its own reentrant lock.
     742                 :            : 
     743                 :            :    2). The prev/next link fields use borrowed references.
     744                 :            : 
     745                 :            :    3). For a full cache, the pure python version rotates the location of the
     746                 :            :        root entry so that it never has to move individual links and it can
     747                 :            :        limit updates to just the key and result fields.  However, in the C
     748                 :            :        version, links are temporarily removed while the cache dict updates are
     749                 :            :        occurring. Afterwards, they are appended or prepended back into the
     750                 :            :        doubly-linked lists.
     751                 :            : 
     752                 :            :    4)  In the Python version, the _HashSeq class is used to prevent __hash__
     753                 :            :        from being called more than once.  In the C version, the "known hash"
     754                 :            :        variants of dictionary calls as used to the same effect.
     755                 :            : 
     756                 :            : */
     757                 :            : 
     758                 :            : struct lru_list_elem;
     759                 :            : struct lru_cache_object;
     760                 :            : 
     761                 :            : typedef struct lru_list_elem {
     762                 :            :     PyObject_HEAD
     763                 :            :     struct lru_list_elem *prev, *next;  /* borrowed links */
     764                 :            :     Py_hash_t hash;
     765                 :            :     PyObject *key, *result;
     766                 :            : } lru_list_elem;
     767                 :            : 
     768                 :            : static void
     769                 :      26813 : lru_list_elem_dealloc(lru_list_elem *link)
     770                 :            : {
     771                 :      26813 :     PyTypeObject *tp = Py_TYPE(link);
     772                 :      26813 :     Py_XDECREF(link->key);
     773                 :      26813 :     Py_XDECREF(link->result);
     774                 :      26813 :     tp->tp_free(link);
     775                 :      26813 :     Py_DECREF(tp);
     776                 :      26813 : }
     777                 :            : 
     778                 :            : static PyType_Slot lru_list_elem_type_slots[] = {
     779                 :            :     {Py_tp_dealloc, lru_list_elem_dealloc},
     780                 :            :     {0, 0}
     781                 :            : };
     782                 :            : 
     783                 :            : static PyType_Spec lru_list_elem_type_spec = {
     784                 :            :     .name = "functools._lru_list_elem",
     785                 :            :     .basicsize = sizeof(lru_list_elem),
     786                 :            :     .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
     787                 :            :              Py_TPFLAGS_IMMUTABLETYPE,
     788                 :            :     .slots = lru_list_elem_type_slots
     789                 :            : };
     790                 :            : 
     791                 :            : 
     792                 :            : typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
     793                 :            : 
     794                 :            : typedef struct lru_cache_object {
     795                 :            :     lru_list_elem root;  /* includes PyObject_HEAD */
     796                 :            :     lru_cache_ternaryfunc wrapper;
     797                 :            :     int typed;
     798                 :            :     PyObject *cache;
     799                 :            :     Py_ssize_t hits;
     800                 :            :     PyObject *func;
     801                 :            :     Py_ssize_t maxsize;
     802                 :            :     Py_ssize_t misses;
     803                 :            :     /* the kwd_mark is used delimit args and keywords in the cache keys */
     804                 :            :     PyObject *kwd_mark;
     805                 :            :     PyTypeObject *lru_list_elem_type;
     806                 :            :     PyObject *cache_info_type;
     807                 :            :     PyObject *dict;
     808                 :            :     PyObject *weakreflist;
     809                 :            : } lru_cache_object;
     810                 :            : 
     811                 :            : static PyObject *
     812                 :    6891895 : lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
     813                 :            :                    PyObject *kwds, int typed)
     814                 :            : {
     815                 :            :     PyObject *key, *keyword, *value;
     816                 :            :     Py_ssize_t key_size, pos, key_pos, kwds_size;
     817                 :            : 
     818         [ +  + ]:    6891895 :     kwds_size = kwds ? PyDict_GET_SIZE(kwds) : 0;
     819                 :            : 
     820                 :            :     /* short path, key will match args anyway, which is a tuple */
     821   [ +  +  +  + ]:    6891895 :     if (!typed && !kwds_size) {
     822         [ +  + ]:    6874388 :         if (PyTuple_GET_SIZE(args) == 1) {
     823                 :    6814410 :             key = PyTuple_GET_ITEM(args, 0);
     824   [ +  +  +  + ]:    6814410 :             if (PyUnicode_CheckExact(key) || PyLong_CheckExact(key)) {
     825                 :            :                 /* For common scalar keys, save space by
     826                 :            :                    dropping the enclosing args tuple  */
     827                 :    6813679 :                 Py_INCREF(key);
     828                 :    6813679 :                 return key;
     829                 :            :             }
     830                 :            :         }
     831                 :      60709 :         Py_INCREF(args);
     832                 :      60709 :         return args;
     833                 :            :     }
     834                 :            : 
     835                 :      17507 :     key_size = PyTuple_GET_SIZE(args);
     836         [ +  + ]:      17507 :     if (kwds_size)
     837                 :        503 :         key_size += kwds_size * 2 + 1;
     838         [ +  + ]:      17507 :     if (typed)
     839                 :      17036 :         key_size += PyTuple_GET_SIZE(args) + kwds_size;
     840                 :            : 
     841                 :      17507 :     key = PyTuple_New(key_size);
     842         [ -  + ]:      17507 :     if (key == NULL)
     843                 :          0 :         return NULL;
     844                 :            : 
     845                 :      17507 :     key_pos = 0;
     846         [ +  + ]:      41692 :     for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
     847                 :      24185 :         PyObject *item = PyTuple_GET_ITEM(args, pos);
     848                 :      24185 :         Py_INCREF(item);
     849                 :      24185 :         PyTuple_SET_ITEM(key, key_pos++, item);
     850                 :            :     }
     851         [ +  + ]:      17507 :     if (kwds_size) {
     852                 :        503 :         Py_INCREF(kwd_mark);
     853                 :        503 :         PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
     854         [ +  + ]:       1040 :         for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
     855                 :        537 :             Py_INCREF(keyword);
     856                 :        537 :             PyTuple_SET_ITEM(key, key_pos++, keyword);
     857                 :        537 :             Py_INCREF(value);
     858                 :        537 :             PyTuple_SET_ITEM(key, key_pos++, value);
     859                 :            :         }
     860                 :            :         assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
     861                 :            :     }
     862         [ +  + ]:      17507 :     if (typed) {
     863         [ +  + ]:      40840 :         for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
     864                 :      23804 :             PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
     865                 :      23804 :             Py_INCREF(item);
     866                 :      23804 :             PyTuple_SET_ITEM(key, key_pos++, item);
     867                 :            :         }
     868         [ +  + ]:      17036 :         if (kwds_size) {
     869         [ +  + ]:         64 :             for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
     870                 :         32 :                 PyObject *item = (PyObject *)Py_TYPE(value);
     871                 :         32 :                 Py_INCREF(item);
     872                 :         32 :                 PyTuple_SET_ITEM(key, key_pos++, item);
     873                 :            :             }
     874                 :            :         }
     875                 :            :     }
     876                 :            :     assert(key_pos == key_size);
     877                 :      17507 :     return key;
     878                 :            : }
     879                 :            : 
     880                 :            : static PyObject *
     881                 :        305 : uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
     882                 :            : {
     883                 :            :     PyObject *result;
     884                 :            : 
     885                 :        305 :     self->misses++;
     886                 :        305 :     result = PyObject_Call(self->func, args, kwds);
     887         [ -  + ]:        305 :     if (!result)
     888                 :          0 :         return NULL;
     889                 :        305 :     return result;
     890                 :            : }
     891                 :            : 
     892                 :            : static PyObject *
     893                 :        127 : infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
     894                 :            : {
     895                 :            :     PyObject *result;
     896                 :            :     Py_hash_t hash;
     897                 :        127 :     PyObject *key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
     898         [ -  + ]:        127 :     if (!key)
     899                 :          0 :         return NULL;
     900                 :        127 :     hash = PyObject_Hash(key);
     901         [ +  + ]:        127 :     if (hash == -1) {
     902                 :          1 :         Py_DECREF(key);
     903                 :          1 :         return NULL;
     904                 :            :     }
     905                 :        126 :     result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
     906         [ +  + ]:        126 :     if (result) {
     907                 :         68 :         Py_INCREF(result);
     908                 :         68 :         self->hits++;
     909                 :         68 :         Py_DECREF(key);
     910                 :         68 :         return result;
     911                 :            :     }
     912         [ -  + ]:         58 :     if (PyErr_Occurred()) {
     913                 :          0 :         Py_DECREF(key);
     914                 :          0 :         return NULL;
     915                 :            :     }
     916                 :         58 :     self->misses++;
     917                 :         58 :     result = PyObject_Call(self->func, args, kwds);
     918         [ +  + ]:         58 :     if (!result) {
     919                 :          2 :         Py_DECREF(key);
     920                 :          2 :         return NULL;
     921                 :            :     }
     922         [ -  + ]:         56 :     if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
     923                 :          0 :         Py_DECREF(result);
     924                 :          0 :         Py_DECREF(key);
     925                 :          0 :         return NULL;
     926                 :            :     }
     927                 :         56 :     Py_DECREF(key);
     928                 :         56 :     return result;
     929                 :            : }
     930                 :            : 
     931                 :            : static void
     932                 :    6864425 : lru_cache_extract_link(lru_list_elem *link)
     933                 :            : {
     934                 :    6864425 :     lru_list_elem *link_prev = link->prev;
     935                 :    6864425 :     lru_list_elem *link_next = link->next;
     936                 :    6864425 :     link_prev->next = link->next;
     937                 :    6864425 :     link_next->prev = link->prev;
     938                 :    6864425 : }
     939                 :            : 
     940                 :            : static void
     941                 :    6891238 : lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
     942                 :            : {
     943                 :    6891238 :     lru_list_elem *root = &self->root;
     944                 :    6891238 :     lru_list_elem *last = root->prev;
     945                 :    6891238 :     last->next = root->prev = link;
     946                 :    6891238 :     link->prev = last;
     947                 :    6891238 :     link->next = root;
     948                 :    6891238 : }
     949                 :            : 
     950                 :            : static void
     951                 :          0 : lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
     952                 :            : {
     953                 :          0 :     lru_list_elem *root = &self->root;
     954                 :          0 :     lru_list_elem *first = root->next;
     955                 :          0 :     first->prev = root->next = link;
     956                 :          0 :     link->prev = root;
     957                 :          0 :     link->next = first;
     958                 :          0 : }
     959                 :            : 
     960                 :            : /* General note on reentrancy:
     961                 :            : 
     962                 :            :    There are four dictionary calls in the bounded_lru_cache_wrapper():
     963                 :            :    1) The initial check for a cache match.  2) The post user-function
     964                 :            :    check for a cache match.  3) The deletion of the oldest entry.
     965                 :            :    4) The addition of the newest entry.
     966                 :            : 
     967                 :            :    In all four calls, we have a known hash which lets use avoid a call
     968                 :            :    to __hash__().  That leaves only __eq__ as a possible source of a
     969                 :            :    reentrant call.
     970                 :            : 
     971                 :            :    The __eq__ method call is always made for a cache hit (dict access #1).
     972                 :            :    Accordingly, we have make sure not modify the cache state prior to
     973                 :            :    this call.
     974                 :            : 
     975                 :            :    The __eq__ method call is never made for the deletion (dict access #3)
     976                 :            :    because it is an identity match.
     977                 :            : 
     978                 :            :    For the other two accesses (#2 and #4), calls to __eq__ only occur
     979                 :            :    when some other entry happens to have an exactly matching hash (all
     980                 :            :    64-bits).  Though rare, this can happen, so we have to make sure to
     981                 :            :    either call it at the top of its code path before any cache
     982                 :            :    state modifications (dict access #2) or be prepared to restore
     983                 :            :    invariants at the end of the code path (dict access #4).
     984                 :            : 
     985                 :            :    Another possible source of reentrancy is a decref which can trigger
     986                 :            :    arbitrary code execution.  To make the code easier to reason about,
     987                 :            :    the decrefs are deferred to the end of the each possible code path
     988                 :            :    so that we know the cache is a consistent state.
     989                 :            :  */
     990                 :            : 
     991                 :            : static PyObject *
     992                 :    6891768 : bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
     993                 :            : {
     994                 :            :     lru_list_elem *link;
     995                 :            :     PyObject *key, *result, *testresult;
     996                 :            :     Py_hash_t hash;
     997                 :            : 
     998                 :    6891768 :     key = lru_cache_make_key(self->kwd_mark, args, kwds, self->typed);
     999         [ -  + ]:    6891768 :     if (!key)
    1000                 :          0 :         return NULL;
    1001                 :    6891768 :     hash = PyObject_Hash(key);
    1002         [ +  + ]:    6891768 :     if (hash == -1) {
    1003                 :         28 :         Py_DECREF(key);
    1004                 :         28 :         return NULL;
    1005                 :            :     }
    1006                 :    6891740 :     link  = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
    1007         [ +  + ]:    6891740 :     if (link != NULL) {
    1008                 :    6860501 :         lru_cache_extract_link(link);
    1009                 :    6860501 :         lru_cache_append_link(self, link);
    1010                 :    6860501 :         result = link->result;
    1011                 :    6860501 :         self->hits++;
    1012                 :    6860501 :         Py_INCREF(result);
    1013                 :    6860501 :         Py_DECREF(key);
    1014                 :    6860501 :         return result;
    1015                 :            :     }
    1016         [ -  + ]:      31239 :     if (PyErr_Occurred()) {
    1017                 :          0 :         Py_DECREF(key);
    1018                 :          0 :         return NULL;
    1019                 :            :     }
    1020                 :      31239 :     self->misses++;
    1021                 :      31239 :     result = PyObject_Call(self->func, args, kwds);
    1022         [ +  + ]:      31239 :     if (!result) {
    1023                 :        471 :         Py_DECREF(key);
    1024                 :        471 :         return NULL;
    1025                 :            :     }
    1026                 :      30768 :     testresult = _PyDict_GetItem_KnownHash(self->cache, key, hash);
    1027         [ +  + ]:      30768 :     if (testresult != NULL) {
    1028                 :            :         /* Getting here means that this same key was added to the cache
    1029                 :            :            during the PyObject_Call().  Since the link update is already
    1030                 :            :            done, we need only return the computed result. */
    1031                 :         31 :         Py_DECREF(key);
    1032                 :         31 :         return result;
    1033                 :            :     }
    1034         [ -  + ]:      30737 :     if (PyErr_Occurred()) {
    1035                 :            :         /* This is an unusual case since this same lookup
    1036                 :            :            did not previously trigger an error during lookup.
    1037                 :            :            Treat it the same as an error in user function
    1038                 :            :            and return with the error set. */
    1039                 :          0 :         Py_DECREF(key);
    1040                 :          0 :         Py_DECREF(result);
    1041                 :          0 :         return NULL;
    1042                 :            :     }
    1043                 :            :     /* This is the normal case.  The new key wasn't found before
    1044                 :            :        user function call and it is still not there.  So we
    1045                 :            :        proceed normally and update the cache with the new result. */
    1046                 :            : 
    1047                 :            :     assert(self->maxsize > 0);
    1048         [ +  + ]:      30737 :     if (PyDict_GET_SIZE(self->cache) < self->maxsize ||
    1049         [ -  + ]:       3924 :         self->root.next == &self->root)
    1050                 :            :     {
    1051                 :            :         /* Cache is not full, so put the result in a new link */
    1052                 :      26813 :         link = (lru_list_elem *)PyObject_New(lru_list_elem,
    1053                 :            :                                              self->lru_list_elem_type);
    1054         [ -  + ]:      26813 :         if (link == NULL) {
    1055                 :          0 :             Py_DECREF(key);
    1056                 :          0 :             Py_DECREF(result);
    1057                 :          0 :             return NULL;
    1058                 :            :         }
    1059                 :            : 
    1060                 :      26813 :         link->hash = hash;
    1061                 :      26813 :         link->key = key;
    1062                 :      26813 :         link->result = result;
    1063                 :            :         /* What is really needed here is a SetItem variant with a "no clobber"
    1064                 :            :            option.  If the __eq__ call triggers a reentrant call that adds
    1065                 :            :            this same key, then this setitem call will update the cache dict
    1066                 :            :            with this new link, leaving the old link as an orphan (i.e. not
    1067                 :            :            having a cache dict entry that refers to it). */
    1068         [ -  + ]:      26813 :         if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
    1069                 :            :                                       hash) < 0) {
    1070                 :          0 :             Py_DECREF(link);
    1071                 :          0 :             return NULL;
    1072                 :            :         }
    1073                 :      26813 :         lru_cache_append_link(self, link);
    1074                 :      26813 :         Py_INCREF(result); /* for return */
    1075                 :      26813 :         return result;
    1076                 :            :     }
    1077                 :            :     /* Since the cache is full, we need to evict an old key and add
    1078                 :            :        a new key.  Rather than free the old link and allocate a new
    1079                 :            :        one, we reuse the link for the new key and result and move it
    1080                 :            :        to front of the cache to mark it as recently used.
    1081                 :            : 
    1082                 :            :        We try to assure all code paths (including errors) leave all
    1083                 :            :        of the links in place.  Either the link is successfully
    1084                 :            :        updated and moved or it is restored to its old position.
    1085                 :            :        However if an unrecoverable error is found, it doesn't
    1086                 :            :        make sense to reinsert the link, so we leave it out
    1087                 :            :        and the cache will no longer register as full.
    1088                 :            :     */
    1089                 :            :     PyObject *oldkey, *oldresult, *popresult;
    1090                 :            : 
    1091                 :            :     /* Extract the oldest item. */
    1092                 :            :     assert(self->root.next != &self->root);
    1093                 :       3924 :     link = self->root.next;
    1094                 :       3924 :     lru_cache_extract_link(link);
    1095                 :            :     /* Remove it from the cache.
    1096                 :            :        The cache dict holds one reference to the link.
    1097                 :            :        We created one other reference when the link was created.
    1098                 :            :        The linked list only has borrowed references. */
    1099                 :       3924 :     popresult = _PyDict_Pop_KnownHash(self->cache, link->key,
    1100                 :            :                                       link->hash, Py_None);
    1101         [ -  + ]:       3924 :     if (popresult == Py_None) {
    1102                 :            :         /* Getting here means that the user function call or another
    1103                 :            :            thread has already removed the old key from the dictionary.
    1104                 :            :            This link is now an orphan.  Since we don't want to leave the
    1105                 :            :            cache in an inconsistent state, we don't restore the link. */
    1106                 :          0 :         Py_DECREF(popresult);
    1107                 :          0 :         Py_DECREF(link);
    1108                 :          0 :         Py_DECREF(key);
    1109                 :          0 :         return result;
    1110                 :            :     }
    1111         [ -  + ]:       3924 :     if (popresult == NULL) {
    1112                 :            :         /* An error arose while trying to remove the oldest key (the one
    1113                 :            :            being evicted) from the cache.  We restore the link to its
    1114                 :            :            original position as the oldest link.  Then we allow the
    1115                 :            :            error propagate upward; treating it the same as an error
    1116                 :            :            arising in the user function. */
    1117                 :          0 :         lru_cache_prepend_link(self, link);
    1118                 :          0 :         Py_DECREF(key);
    1119                 :          0 :         Py_DECREF(result);
    1120                 :          0 :         return NULL;
    1121                 :            :     }
    1122                 :            :     /* Keep a reference to the old key and old result to prevent their
    1123                 :            :        ref counts from going to zero during the update. That will
    1124                 :            :        prevent potentially arbitrary object clean-up code (i.e. __del__)
    1125                 :            :        from running while we're still adjusting the links. */
    1126                 :       3924 :     oldkey = link->key;
    1127                 :       3924 :     oldresult = link->result;
    1128                 :            : 
    1129                 :       3924 :     link->hash = hash;
    1130                 :       3924 :     link->key = key;
    1131                 :       3924 :     link->result = result;
    1132                 :            :     /* Note:  The link is being added to the cache dict without the
    1133                 :            :        prev and next fields set to valid values.   We have to wait
    1134                 :            :        for successful insertion in the cache dict before adding the
    1135                 :            :        link to the linked list.  Otherwise, the potentially reentrant
    1136                 :            :        __eq__ call could cause the then orphan link to be visited. */
    1137         [ -  + ]:       3924 :     if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
    1138                 :            :                                   hash) < 0) {
    1139                 :            :         /* Somehow the cache dict update failed.  We no longer can
    1140                 :            :            restore the old link.  Let the error propagate upward and
    1141                 :            :            leave the cache short one link. */
    1142                 :          0 :         Py_DECREF(popresult);
    1143                 :          0 :         Py_DECREF(link);
    1144                 :          0 :         Py_DECREF(oldkey);
    1145                 :          0 :         Py_DECREF(oldresult);
    1146                 :          0 :         return NULL;
    1147                 :            :     }
    1148                 :       3924 :     lru_cache_append_link(self, link);
    1149                 :       3924 :     Py_INCREF(result); /* for return */
    1150                 :       3924 :     Py_DECREF(popresult);
    1151                 :       3924 :     Py_DECREF(oldkey);
    1152                 :       3924 :     Py_DECREF(oldresult);
    1153                 :       3924 :     return result;
    1154                 :            : }
    1155                 :            : 
    1156                 :            : static PyObject *
    1157                 :      14963 : lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
    1158                 :            : {
    1159                 :            :     PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
    1160                 :            :     int typed;
    1161                 :            :     lru_cache_object *obj;
    1162                 :            :     Py_ssize_t maxsize;
    1163                 :            :     PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
    1164                 :            :     _functools_state *state;
    1165                 :            :     static char *keywords[] = {"user_function", "maxsize", "typed",
    1166                 :            :                                "cache_info_type", NULL};
    1167                 :            : 
    1168         [ -  + ]:      14963 :     if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
    1169                 :            :                                      &func, &maxsize_O, &typed,
    1170                 :            :                                      &cache_info_type)) {
    1171                 :          0 :         return NULL;
    1172                 :            :     }
    1173                 :            : 
    1174         [ -  + ]:      14963 :     if (!PyCallable_Check(func)) {
    1175                 :          0 :         PyErr_SetString(PyExc_TypeError,
    1176                 :            :                         "the first argument must be callable");
    1177                 :          0 :         return NULL;
    1178                 :            :     }
    1179                 :            : 
    1180                 :      14963 :     state = get_functools_state_by_type(type);
    1181         [ -  + ]:      14963 :     if (state == NULL) {
    1182                 :          0 :         return NULL;
    1183                 :            :     }
    1184                 :            : 
    1185                 :            :     /* select the caching function, and make/inc maxsize_O */
    1186         [ +  + ]:      14963 :     if (maxsize_O == Py_None) {
    1187                 :         98 :         wrapper = infinite_lru_cache_wrapper;
    1188                 :            :         /* use this only to initialize lru_cache_object attribute maxsize */
    1189                 :         98 :         maxsize = -1;
    1190         [ +  - ]:      14865 :     } else if (PyIndex_Check(maxsize_O)) {
    1191                 :      14865 :         maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
    1192   [ -  +  -  - ]:      14865 :         if (maxsize == -1 && PyErr_Occurred())
    1193                 :          0 :             return NULL;
    1194         [ -  + ]:      14865 :         if (maxsize < 0) {
    1195                 :          0 :             maxsize = 0;
    1196                 :            :         }
    1197         [ +  + ]:      14865 :         if (maxsize == 0)
    1198                 :          2 :             wrapper = uncached_lru_cache_wrapper;
    1199                 :            :         else
    1200                 :      14863 :             wrapper = bounded_lru_cache_wrapper;
    1201                 :            :     } else {
    1202                 :          0 :         PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
    1203                 :          0 :         return NULL;
    1204                 :            :     }
    1205                 :            : 
    1206         [ -  + ]:      14963 :     if (!(cachedict = PyDict_New()))
    1207                 :          0 :         return NULL;
    1208                 :            : 
    1209                 :      14963 :     obj = (lru_cache_object *)type->tp_alloc(type, 0);
    1210         [ -  + ]:      14963 :     if (obj == NULL) {
    1211                 :          0 :         Py_DECREF(cachedict);
    1212                 :          0 :         return NULL;
    1213                 :            :     }
    1214                 :            : 
    1215                 :      14963 :     obj->root.prev = &obj->root;
    1216                 :      14963 :     obj->root.next = &obj->root;
    1217                 :      14963 :     obj->wrapper = wrapper;
    1218                 :      14963 :     obj->typed = typed;
    1219                 :      14963 :     obj->cache = cachedict;
    1220                 :      14963 :     Py_INCREF(func);
    1221                 :      14963 :     obj->func = func;
    1222                 :      14963 :     obj->misses = obj->hits = 0;
    1223                 :      14963 :     obj->maxsize = maxsize;
    1224                 :      14963 :     Py_INCREF(state->kwd_mark);
    1225                 :      14963 :     obj->kwd_mark = state->kwd_mark;
    1226                 :      14963 :     Py_INCREF(state->lru_list_elem_type);
    1227                 :      14963 :     obj->lru_list_elem_type = state->lru_list_elem_type;
    1228                 :      14963 :     Py_INCREF(cache_info_type);
    1229                 :      14963 :     obj->cache_info_type = cache_info_type;
    1230                 :      14963 :     obj->dict = NULL;
    1231                 :      14963 :     obj->weakreflist = NULL;
    1232                 :      14963 :     return (PyObject *)obj;
    1233                 :            : }
    1234                 :            : 
    1235                 :            : static lru_list_elem *
    1236                 :      19749 : lru_cache_unlink_list(lru_cache_object *self)
    1237                 :            : {
    1238                 :      19749 :     lru_list_elem *root = &self->root;
    1239                 :      19749 :     lru_list_elem *link = root->next;
    1240         [ +  + ]:      19749 :     if (link == root)
    1241                 :      14088 :         return NULL;
    1242                 :       5661 :     root->prev->next = NULL;
    1243                 :       5661 :     root->next = root->prev = root;
    1244                 :       5661 :     return link;
    1245                 :            : }
    1246                 :            : 
    1247                 :            : static void
    1248                 :      19749 : lru_cache_clear_list(lru_list_elem *link)
    1249                 :            : {
    1250         [ +  + ]:      46562 :     while (link != NULL) {
    1251                 :      26813 :         lru_list_elem *next = link->next;
    1252                 :      26813 :         Py_DECREF(link);
    1253                 :      26813 :         link = next;
    1254                 :            :     }
    1255                 :      19749 : }
    1256                 :            : 
    1257                 :            : static int
    1258                 :      15021 : lru_cache_tp_clear(lru_cache_object *self)
    1259                 :            : {
    1260                 :      15021 :     lru_list_elem *list = lru_cache_unlink_list(self);
    1261         [ +  + ]:      15021 :     Py_CLEAR(self->cache);
    1262         [ +  + ]:      15021 :     Py_CLEAR(self->func);
    1263         [ +  + ]:      15021 :     Py_CLEAR(self->kwd_mark);
    1264         [ +  + ]:      15021 :     Py_CLEAR(self->lru_list_elem_type);
    1265         [ +  + ]:      15021 :     Py_CLEAR(self->cache_info_type);
    1266         [ +  + ]:      15021 :     Py_CLEAR(self->dict);
    1267                 :      15021 :     lru_cache_clear_list(list);
    1268                 :      15021 :     return 0;
    1269                 :            : }
    1270                 :            : 
    1271                 :            : static void
    1272                 :      14953 : lru_cache_dealloc(lru_cache_object *obj)
    1273                 :            : {
    1274                 :      14953 :     PyTypeObject *tp = Py_TYPE(obj);
    1275                 :            :     /* bpo-31095: UnTrack is needed before calling any callbacks */
    1276                 :      14953 :     PyObject_GC_UnTrack(obj);
    1277         [ +  + ]:      14953 :     if (obj->weakreflist != NULL) {
    1278                 :          1 :         PyObject_ClearWeakRefs((PyObject*)obj);
    1279                 :            :     }
    1280                 :            : 
    1281                 :      14953 :     (void)lru_cache_tp_clear(obj);
    1282                 :      14953 :     tp->tp_free(obj);
    1283                 :      14953 :     Py_DECREF(tp);
    1284                 :      14953 : }
    1285                 :            : 
    1286                 :            : static PyObject *
    1287                 :    6892200 : lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
    1288                 :            : {
    1289                 :    6892200 :     return self->wrapper(self, args, kwds);
    1290                 :            : }
    1291                 :            : 
    1292                 :            : static PyObject *
    1293                 :       1389 : lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
    1294                 :            : {
    1295   [ +  -  +  + ]:       1389 :     if (obj == Py_None || obj == NULL) {
    1296                 :        298 :         Py_INCREF(self);
    1297                 :        298 :         return self;
    1298                 :            :     }
    1299                 :       1091 :     return PyMethod_New(self, obj);
    1300                 :            : }
    1301                 :            : 
    1302                 :            : static PyObject *
    1303                 :         54 : lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
    1304                 :            : {
    1305         [ +  + ]:         54 :     if (self->maxsize == -1) {
    1306                 :          6 :         return PyObject_CallFunction(self->cache_info_type, "nnOn",
    1307                 :            :                                      self->hits, self->misses, Py_None,
    1308                 :            :                                      PyDict_GET_SIZE(self->cache));
    1309                 :            :     }
    1310                 :         48 :     return PyObject_CallFunction(self->cache_info_type, "nnnn",
    1311                 :            :                                  self->hits, self->misses, self->maxsize,
    1312                 :            :                                  PyDict_GET_SIZE(self->cache));
    1313                 :            : }
    1314                 :            : 
    1315                 :            : static PyObject *
    1316                 :       4728 : lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
    1317                 :            : {
    1318                 :       4728 :     lru_list_elem *list = lru_cache_unlink_list(self);
    1319                 :       4728 :     self->hits = self->misses = 0;
    1320                 :       4728 :     PyDict_Clear(self->cache);
    1321                 :       4728 :     lru_cache_clear_list(list);
    1322                 :       4728 :     Py_RETURN_NONE;
    1323                 :            : }
    1324                 :            : 
    1325                 :            : static PyObject *
    1326                 :         18 : lru_cache_reduce(PyObject *self, PyObject *unused)
    1327                 :            : {
    1328                 :         18 :     return PyObject_GetAttrString(self, "__qualname__");
    1329                 :            : }
    1330                 :            : 
    1331                 :            : static PyObject *
    1332                 :          4 : lru_cache_copy(PyObject *self, PyObject *unused)
    1333                 :            : {
    1334                 :          4 :     Py_INCREF(self);
    1335                 :          4 :     return self;
    1336                 :            : }
    1337                 :            : 
    1338                 :            : static PyObject *
    1339                 :          4 : lru_cache_deepcopy(PyObject *self, PyObject *unused)
    1340                 :            : {
    1341                 :          4 :     Py_INCREF(self);
    1342                 :          4 :     return self;
    1343                 :            : }
    1344                 :            : 
    1345                 :            : static int
    1346                 :     458266 : lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
    1347                 :            : {
    1348   [ +  -  -  + ]:     458266 :     Py_VISIT(Py_TYPE(self));
    1349                 :     458266 :     lru_list_elem *link = self->root.next;
    1350         [ +  + ]:     814574 :     while (link != &self->root) {
    1351                 :     356308 :         lru_list_elem *next = link->next;
    1352   [ +  -  -  + ]:     356308 :         Py_VISIT(link->key);
    1353   [ +  -  -  + ]:     356308 :         Py_VISIT(link->result);
    1354   [ +  -  -  + ]:     356308 :         Py_VISIT(Py_TYPE(link));
    1355                 :     356308 :         link = next;
    1356                 :            :     }
    1357   [ +  -  -  + ]:     458266 :     Py_VISIT(self->cache);
    1358   [ +  -  -  + ]:     458266 :     Py_VISIT(self->func);
    1359   [ +  -  -  + ]:     458266 :     Py_VISIT(self->kwd_mark);
    1360   [ +  -  -  + ]:     458266 :     Py_VISIT(self->lru_list_elem_type);
    1361   [ +  -  -  + ]:     458266 :     Py_VISIT(self->cache_info_type);
    1362   [ +  +  -  + ]:     458266 :     Py_VISIT(self->dict);
    1363                 :     458266 :     return 0;
    1364                 :            : }
    1365                 :            : 
    1366                 :            : 
    1367                 :            : PyDoc_STRVAR(lru_cache_doc,
    1368                 :            : "Create a cached callable that wraps another function.\n\
    1369                 :            : \n\
    1370                 :            : user_function:      the function being cached\n\
    1371                 :            : \n\
    1372                 :            : maxsize:  0         for no caching\n\
    1373                 :            :           None      for unlimited cache size\n\
    1374                 :            :           n         for a bounded cache\n\
    1375                 :            : \n\
    1376                 :            : typed:    False     cache f(3) and f(3.0) as identical calls\n\
    1377                 :            :           True      cache f(3) and f(3.0) as distinct calls\n\
    1378                 :            : \n\
    1379                 :            : cache_info_type:    namedtuple class with the fields:\n\
    1380                 :            :                         hits misses currsize maxsize\n"
    1381                 :            : );
    1382                 :            : 
    1383                 :            : static PyMethodDef lru_cache_methods[] = {
    1384                 :            :     {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
    1385                 :            :     {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
    1386                 :            :     {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
    1387                 :            :     {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
    1388                 :            :     {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
    1389                 :            :     {NULL}
    1390                 :            : };
    1391                 :            : 
    1392                 :            : static PyGetSetDef lru_cache_getsetlist[] = {
    1393                 :            :     {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
    1394                 :            :     {NULL}
    1395                 :            : };
    1396                 :            : 
    1397                 :            : static PyMemberDef lru_cache_memberlist[] = {
    1398                 :            :     {"__dictoffset__", T_PYSSIZET,
    1399                 :            :      offsetof(lru_cache_object, dict), READONLY},
    1400                 :            :     {"__weaklistoffset__", T_PYSSIZET,
    1401                 :            :      offsetof(lru_cache_object, weakreflist), READONLY},
    1402                 :            :     {NULL}  /* Sentinel */
    1403                 :            : };
    1404                 :            : 
    1405                 :            : static PyType_Slot lru_cache_type_slots[] = {
    1406                 :            :     {Py_tp_dealloc, lru_cache_dealloc},
    1407                 :            :     {Py_tp_call, lru_cache_call},
    1408                 :            :     {Py_tp_doc, (void *)lru_cache_doc},
    1409                 :            :     {Py_tp_traverse, lru_cache_tp_traverse},
    1410                 :            :     {Py_tp_clear, lru_cache_tp_clear},
    1411                 :            :     {Py_tp_methods, lru_cache_methods},
    1412                 :            :     {Py_tp_members, lru_cache_memberlist},
    1413                 :            :     {Py_tp_getset, lru_cache_getsetlist},
    1414                 :            :     {Py_tp_descr_get, lru_cache_descr_get},
    1415                 :            :     {Py_tp_new, lru_cache_new},
    1416                 :            :     {0, 0}
    1417                 :            : };
    1418                 :            : 
    1419                 :            : static PyType_Spec lru_cache_type_spec = {
    1420                 :            :     .name = "functools._lru_cache_wrapper",
    1421                 :            :     .basicsize = sizeof(lru_cache_object),
    1422                 :            :     .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
    1423                 :            :              Py_TPFLAGS_METHOD_DESCRIPTOR | Py_TPFLAGS_IMMUTABLETYPE,
    1424                 :            :     .slots = lru_cache_type_slots
    1425                 :            : };
    1426                 :            : 
    1427                 :            : 
    1428                 :            : /* module level code ********************************************************/
    1429                 :            : 
    1430                 :            : PyDoc_STRVAR(_functools_doc,
    1431                 :            : "Tools that operate on functions.");
    1432                 :            : 
    1433                 :            : static PyMethodDef _functools_methods[] = {
    1434                 :            :     {"reduce",          functools_reduce,     METH_VARARGS, functools_reduce_doc},
    1435                 :            :     {"cmp_to_key",      _PyCFunction_CAST(functools_cmp_to_key),
    1436                 :            :      METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
    1437                 :            :     {NULL,              NULL}           /* sentinel */
    1438                 :            : };
    1439                 :            : 
    1440                 :            : static int
    1441                 :       1982 : _functools_exec(PyObject *module)
    1442                 :            : {
    1443                 :       1982 :     _functools_state *state = get_functools_state(module);
    1444                 :       1982 :     state->kwd_mark = _PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type);
    1445         [ -  + ]:       1982 :     if (state->kwd_mark == NULL) {
    1446                 :          0 :         return -1;
    1447                 :            :     }
    1448                 :            : 
    1449                 :       1982 :     state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
    1450                 :            :         &partial_type_spec, NULL);
    1451         [ -  + ]:       1982 :     if (state->partial_type == NULL) {
    1452                 :          0 :         return -1;
    1453                 :            :     }
    1454         [ -  + ]:       1982 :     if (PyModule_AddType(module, state->partial_type) < 0) {
    1455                 :          0 :         return -1;
    1456                 :            :     }
    1457                 :            : 
    1458                 :       1982 :     PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
    1459                 :            :         &lru_cache_type_spec, NULL);
    1460         [ -  + ]:       1982 :     if (lru_cache_type == NULL) {
    1461                 :          0 :         return -1;
    1462                 :            :     }
    1463         [ -  + ]:       1982 :     if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
    1464                 :          0 :         Py_DECREF(lru_cache_type);
    1465                 :          0 :         return -1;
    1466                 :            :     }
    1467                 :       1982 :     Py_DECREF(lru_cache_type);
    1468                 :            : 
    1469                 :       1982 :     state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
    1470                 :            :         &keyobject_type_spec, NULL);
    1471         [ -  + ]:       1982 :     if (state->keyobject_type == NULL) {
    1472                 :          0 :         return -1;
    1473                 :            :     }
    1474         [ -  + ]:       1982 :     if (PyModule_AddType(module, state->keyobject_type) < 0) {
    1475                 :          0 :         return -1;
    1476                 :            :     }
    1477                 :            : 
    1478                 :       1982 :     state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
    1479                 :            :         module, &lru_list_elem_type_spec, NULL);
    1480         [ -  + ]:       1982 :     if (state->lru_list_elem_type == NULL) {
    1481                 :          0 :         return -1;
    1482                 :            :     }
    1483                 :            :     // lru_list_elem is used only in _lru_cache_wrapper.
    1484                 :            :     // So we don't expose it in module namespace.
    1485                 :            : 
    1486                 :       1982 :     return 0;
    1487                 :            : }
    1488                 :            : 
    1489                 :            : static int
    1490                 :      47190 : _functools_traverse(PyObject *module, visitproc visit, void *arg)
    1491                 :            : {
    1492                 :      47190 :     _functools_state *state = get_functools_state(module);
    1493   [ +  -  -  + ]:      47190 :     Py_VISIT(state->kwd_mark);
    1494   [ +  +  -  + ]:      47190 :     Py_VISIT(state->partial_type);
    1495   [ +  +  -  + ]:      47190 :     Py_VISIT(state->keyobject_type);
    1496   [ +  +  -  + ]:      47190 :     Py_VISIT(state->lru_list_elem_type);
    1497                 :      47190 :     return 0;
    1498                 :            : }
    1499                 :            : 
    1500                 :            : static int
    1501                 :       3894 : _functools_clear(PyObject *module)
    1502                 :            : {
    1503                 :       3894 :     _functools_state *state = get_functools_state(module);
    1504         [ +  + ]:       3894 :     Py_CLEAR(state->kwd_mark);
    1505         [ +  + ]:       3894 :     Py_CLEAR(state->partial_type);
    1506         [ +  + ]:       3894 :     Py_CLEAR(state->keyobject_type);
    1507         [ +  + ]:       3894 :     Py_CLEAR(state->lru_list_elem_type);
    1508                 :       3894 :     return 0;
    1509                 :            : }
    1510                 :            : 
    1511                 :            : static void
    1512                 :       1947 : _functools_free(void *module)
    1513                 :            : {
    1514                 :       1947 :     _functools_clear((PyObject *)module);
    1515                 :       1947 : }
    1516                 :            : 
    1517                 :            : static struct PyModuleDef_Slot _functools_slots[] = {
    1518                 :            :     {Py_mod_exec, _functools_exec},
    1519                 :            :     {0, NULL}
    1520                 :            : };
    1521                 :            : 
    1522                 :            : static struct PyModuleDef _functools_module = {
    1523                 :            :     PyModuleDef_HEAD_INIT,
    1524                 :            :     .m_name = "_functools",
    1525                 :            :     .m_doc = _functools_doc,
    1526                 :            :     .m_size = sizeof(_functools_state),
    1527                 :            :     .m_methods = _functools_methods,
    1528                 :            :     .m_slots = _functools_slots,
    1529                 :            :     .m_traverse = _functools_traverse,
    1530                 :            :     .m_clear = _functools_clear,
    1531                 :            :     .m_free = _functools_free,
    1532                 :            : };
    1533                 :            : 
    1534                 :            : PyMODINIT_FUNC
    1535                 :       1982 : PyInit__functools(void)
    1536                 :            : {
    1537                 :       1982 :     return PyModuleDef_Init(&_functools_module);
    1538                 :            : }

Generated by: LCOV version 1.14