blob: f785a7260e6a2e07954f104ebaa3e59b3ed24560 [file] [log] [blame]
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001
2#include "Python.h"
3#include "structmember.h"
4
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00005/* _functools module written and maintained
Raymond Hettinger9c323f82005-02-28 19:39:44 +00006 by Hye-Shik Chang <perky@FreeBSD.org>
7 with adaptations by Raymond Hettinger <python@rcn.com>
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00008 Copyright (c) 2004, 2005, 2006 Python Software Foundation.
Raymond Hettinger9c323f82005-02-28 19:39:44 +00009 All rights reserved.
10*/
11
12/* partial object **********************************************************/
13
14typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000015 PyObject_HEAD
16 PyObject *fn;
17 PyObject *args;
18 PyObject *kw;
19 PyObject *dict;
20 PyObject *weakreflist; /* List of weak references */
Raymond Hettinger9c323f82005-02-28 19:39:44 +000021} partialobject;
22
23static PyTypeObject partial_type;
24
25static PyObject *
26partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
27{
Alexander Belopolskye49af342015-03-01 15:08:17 -050028 PyObject *func, *pargs, *nargs, *pkw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000029 partialobject *pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000030
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000031 if (PyTuple_GET_SIZE(args) < 1) {
32 PyErr_SetString(PyExc_TypeError,
33 "type 'partial' takes at least one argument");
34 return NULL;
35 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000036
Serhiy Storchaka38741282016-02-02 18:45:17 +020037 pargs = pkw = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000038 func = PyTuple_GET_ITEM(args, 0);
Alexander Belopolskye49af342015-03-01 15:08:17 -050039 if (Py_TYPE(func) == &partial_type && type == &partial_type) {
40 partialobject *part = (partialobject *)func;
41 if (part->dict == NULL) {
42 pargs = part->args;
43 pkw = part->kw;
44 func = part->fn;
Serhiy Storchaka38741282016-02-02 18:45:17 +020045 assert(PyTuple_Check(pargs));
46 assert(PyDict_Check(pkw));
Alexander Belopolskye49af342015-03-01 15:08:17 -050047 }
48 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000049 if (!PyCallable_Check(func)) {
50 PyErr_SetString(PyExc_TypeError,
51 "the first argument must be callable");
52 return NULL;
53 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +000054
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000055 /* create partialobject structure */
56 pto = (partialobject *)type->tp_alloc(type, 0);
57 if (pto == NULL)
58 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +000059
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 pto->fn = func;
61 Py_INCREF(func);
Alexander Belopolskye49af342015-03-01 15:08:17 -050062
63 nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
64 if (nargs == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000065 Py_DECREF(pto);
66 return NULL;
67 }
Serhiy Storchaka38741282016-02-02 18:45:17 +020068 if (pargs == NULL || PyTuple_GET_SIZE(pargs) == 0) {
Alexander Belopolskye49af342015-03-01 15:08:17 -050069 pto->args = nargs;
70 Py_INCREF(nargs);
71 }
72 else if (PyTuple_GET_SIZE(nargs) == 0) {
73 pto->args = pargs;
74 Py_INCREF(pargs);
75 }
76 else {
77 pto->args = PySequence_Concat(pargs, nargs);
78 if (pto->args == NULL) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020079 Py_DECREF(nargs);
Alexander Belopolskye49af342015-03-01 15:08:17 -050080 Py_DECREF(pto);
81 return NULL;
82 }
Serhiy Storchaka38741282016-02-02 18:45:17 +020083 assert(PyTuple_Check(pto->args));
Alexander Belopolskye49af342015-03-01 15:08:17 -050084 }
85 Py_DECREF(nargs);
86
Serhiy Storchaka38741282016-02-02 18:45:17 +020087 if (pkw == NULL || PyDict_Size(pkw) == 0) {
88 if (kw == NULL) {
89 pto->kw = PyDict_New();
Alexander Belopolskye49af342015-03-01 15:08:17 -050090 }
91 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +020092 Py_INCREF(kw);
93 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000094 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050095 }
96 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +020097 pto->kw = PyDict_Copy(pkw);
98 if (kw != NULL && pto->kw != NULL) {
99 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -0400100 Py_DECREF(pto);
101 return NULL;
102 }
103 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200105 if (pto->kw == NULL) {
106 Py_DECREF(pto);
107 return NULL;
108 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000109
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 return (PyObject *)pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000111}
112
113static void
114partial_dealloc(partialobject *pto)
115{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000116 PyObject_GC_UnTrack(pto);
117 if (pto->weakreflist != NULL)
118 PyObject_ClearWeakRefs((PyObject *) pto);
119 Py_XDECREF(pto->fn);
120 Py_XDECREF(pto->args);
121 Py_XDECREF(pto->kw);
122 Py_XDECREF(pto->dict);
123 Py_TYPE(pto)->tp_free(pto);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000124}
125
126static PyObject *
127partial_call(partialobject *pto, PyObject *args, PyObject *kw)
128{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129 PyObject *ret;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200130 PyObject *argappl, *kwappl;
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200131 PyObject **stack;
132 Py_ssize_t nargs;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000133
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000134 assert (PyCallable_Check(pto->fn));
135 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200136 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000137
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000138 if (PyTuple_GET_SIZE(pto->args) == 0) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200139 stack = &PyTuple_GET_ITEM(args, 0);
140 nargs = PyTuple_GET_SIZE(args);
141 argappl = NULL;
142 }
143 else if (PyTuple_GET_SIZE(args) == 0) {
144 stack = &PyTuple_GET_ITEM(pto->args, 0);
145 nargs = PyTuple_GET_SIZE(pto->args);
146 argappl = NULL;
147 }
148 else {
149 stack = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000150 argappl = PySequence_Concat(pto->args, args);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200151 if (argappl == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000152 return NULL;
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200153 }
154
Serhiy Storchaka38741282016-02-02 18:45:17 +0200155 assert(PyTuple_Check(argappl));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000156 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000157
Serhiy Storchaka38741282016-02-02 18:45:17 +0200158 if (PyDict_Size(pto->kw) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 kwappl = kw;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200160 Py_XINCREF(kwappl);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200161 }
162 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000163 kwappl = PyDict_Copy(pto->kw);
164 if (kwappl == NULL) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200165 Py_XDECREF(argappl);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 return NULL;
167 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200168
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000169 if (kw != NULL) {
170 if (PyDict_Merge(kwappl, kw, 1) != 0) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200171 Py_XDECREF(argappl);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 Py_DECREF(kwappl);
173 return NULL;
174 }
175 }
176 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000177
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200178 if (stack) {
179 ret = _PyObject_FastCallDict(pto->fn, stack, nargs, kwappl);
180 }
181 else {
182 ret = PyObject_Call(pto->fn, argappl, kwappl);
183 Py_DECREF(argappl);
184 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000185 Py_XDECREF(kwappl);
186 return ret;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000187}
188
189static int
190partial_traverse(partialobject *pto, visitproc visit, void *arg)
191{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000192 Py_VISIT(pto->fn);
193 Py_VISIT(pto->args);
194 Py_VISIT(pto->kw);
195 Py_VISIT(pto->dict);
196 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000197}
198
199PyDoc_STRVAR(partial_doc,
200"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000202
203#define OFF(x) offsetof(partialobject, x)
204static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000205 {"func", T_OBJECT, OFF(fn), READONLY,
206 "function object to use in future partial calls"},
207 {"args", T_OBJECT, OFF(args), READONLY,
208 "tuple of arguments to future partial calls"},
209 {"keywords", T_OBJECT, OFF(kw), READONLY,
210 "dictionary of keyword arguments to future partial calls"},
211 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000212};
213
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000214static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500215 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000216 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000217};
218
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000219static PyObject *
220partial_repr(partialobject *pto)
221{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300222 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000223 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000224 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200225 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300226 int status;
227
228 status = Py_ReprEnter((PyObject *)pto);
229 if (status != 0) {
230 if (status < 0)
231 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000232 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300233 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000234
235 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300236 if (arglist == NULL)
237 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000238 /* Pack positional arguments */
239 assert (PyTuple_Check(pto->args));
240 n = PyTuple_GET_SIZE(pto->args);
241 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300242 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
243 PyTuple_GET_ITEM(pto->args, i)));
244 if (arglist == NULL)
245 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000246 }
247 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200248 assert (PyDict_Check(pto->kw));
249 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300250 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %U=%R", arglist,
251 key, value));
252 if (arglist == NULL)
253 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000254 }
255 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
256 pto->fn, arglist);
257 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300258
259 done:
260 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000261 return result;
262}
263
Jack Diederiche0cbd692009-04-01 04:27:09 +0000264/* Pickle strategy:
265 __reduce__ by itself doesn't support getting kwargs in the unpickle
266 operation so we define a __setstate__ that replaces all the information
267 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200268 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000269 */
270
Antoine Pitrou69f71142009-05-24 21:25:49 +0000271static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000272partial_reduce(partialobject *pto, PyObject *unused)
273{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
275 pto->args, pto->kw,
276 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000277}
278
Antoine Pitrou69f71142009-05-24 21:25:49 +0000279static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200280partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000281{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200283
284 if (!PyTuple_Check(state) ||
285 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
286 !PyCallable_Check(fn) ||
287 !PyTuple_Check(fnargs) ||
288 (kw != Py_None && !PyDict_Check(kw)))
289 {
290 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000292 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200293
294 if(!PyTuple_CheckExact(fnargs))
295 fnargs = PySequence_Tuple(fnargs);
296 else
297 Py_INCREF(fnargs);
298 if (fnargs == NULL)
299 return NULL;
300
301 if (kw == Py_None)
302 kw = PyDict_New();
303 else if(!PyDict_CheckExact(kw))
304 kw = PyDict_Copy(kw);
305 else
306 Py_INCREF(kw);
307 if (kw == NULL) {
308 Py_DECREF(fnargs);
309 return NULL;
310 }
311
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 Py_INCREF(fn);
Serhiy Storchaka38741282016-02-02 18:45:17 +0200313 if (dict == Py_None)
314 dict = NULL;
315 else
316 Py_INCREF(dict);
317
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300318 Py_SETREF(pto->fn, fn);
319 Py_SETREF(pto->args, fnargs);
320 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300321 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000323}
324
325static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000326 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200327 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000328 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000329};
330
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000331static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 PyVarObject_HEAD_INIT(NULL, 0)
333 "functools.partial", /* tp_name */
334 sizeof(partialobject), /* tp_basicsize */
335 0, /* tp_itemsize */
336 /* methods */
337 (destructor)partial_dealloc, /* tp_dealloc */
338 0, /* tp_print */
339 0, /* tp_getattr */
340 0, /* tp_setattr */
341 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000342 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 0, /* tp_as_number */
344 0, /* tp_as_sequence */
345 0, /* tp_as_mapping */
346 0, /* tp_hash */
347 (ternaryfunc)partial_call, /* tp_call */
348 0, /* tp_str */
349 PyObject_GenericGetAttr, /* tp_getattro */
350 PyObject_GenericSetAttr, /* tp_setattro */
351 0, /* tp_as_buffer */
352 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
353 Py_TPFLAGS_BASETYPE, /* tp_flags */
354 partial_doc, /* tp_doc */
355 (traverseproc)partial_traverse, /* tp_traverse */
356 0, /* tp_clear */
357 0, /* tp_richcompare */
358 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
359 0, /* tp_iter */
360 0, /* tp_iternext */
361 partial_methods, /* tp_methods */
362 partial_memberlist, /* tp_members */
363 partial_getsetlist, /* tp_getset */
364 0, /* tp_base */
365 0, /* tp_dict */
366 0, /* tp_descr_get */
367 0, /* tp_descr_set */
368 offsetof(partialobject, dict), /* tp_dictoffset */
369 0, /* tp_init */
370 0, /* tp_alloc */
371 partial_new, /* tp_new */
372 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000373};
374
375
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700376/* cmp_to_key ***************************************************************/
377
378typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200379 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700380 PyObject *cmp;
381 PyObject *object;
382} keyobject;
383
384static void
385keyobject_dealloc(keyobject *ko)
386{
387 Py_DECREF(ko->cmp);
388 Py_XDECREF(ko->object);
389 PyObject_FREE(ko);
390}
391
392static int
393keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
394{
395 Py_VISIT(ko->cmp);
396 if (ko->object)
397 Py_VISIT(ko->object);
398 return 0;
399}
400
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500401static int
402keyobject_clear(keyobject *ko)
403{
404 Py_CLEAR(ko->cmp);
405 if (ko->object)
406 Py_CLEAR(ko->object);
407 return 0;
408}
409
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700410static PyMemberDef keyobject_members[] = {
411 {"obj", T_OBJECT,
412 offsetof(keyobject, object), 0,
413 PyDoc_STR("Value wrapped by a key function.")},
414 {NULL}
415};
416
417static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700418keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700419
420static PyObject *
421keyobject_richcompare(PyObject *ko, PyObject *other, int op);
422
423static PyTypeObject keyobject_type = {
424 PyVarObject_HEAD_INIT(&PyType_Type, 0)
425 "functools.KeyWrapper", /* tp_name */
426 sizeof(keyobject), /* tp_basicsize */
427 0, /* tp_itemsize */
428 /* methods */
429 (destructor)keyobject_dealloc, /* tp_dealloc */
430 0, /* tp_print */
431 0, /* tp_getattr */
432 0, /* tp_setattr */
433 0, /* tp_reserved */
434 0, /* tp_repr */
435 0, /* tp_as_number */
436 0, /* tp_as_sequence */
437 0, /* tp_as_mapping */
438 0, /* tp_hash */
439 (ternaryfunc)keyobject_call, /* tp_call */
440 0, /* tp_str */
441 PyObject_GenericGetAttr, /* tp_getattro */
442 0, /* tp_setattro */
443 0, /* tp_as_buffer */
444 Py_TPFLAGS_DEFAULT, /* tp_flags */
445 0, /* tp_doc */
446 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500447 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700448 keyobject_richcompare, /* tp_richcompare */
449 0, /* tp_weaklistoffset */
450 0, /* tp_iter */
451 0, /* tp_iternext */
452 0, /* tp_methods */
453 keyobject_members, /* tp_members */
454 0, /* tp_getset */
455};
456
457static PyObject *
458keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
459{
460 PyObject *object;
461 keyobject *result;
462 static char *kwargs[] = {"obj", NULL};
463
464 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
465 return NULL;
466 result = PyObject_New(keyobject, &keyobject_type);
467 if (!result)
468 return NULL;
469 Py_INCREF(ko->cmp);
470 result->cmp = ko->cmp;
471 Py_INCREF(object);
472 result->object = object;
473 return (PyObject *)result;
474}
475
476static PyObject *
477keyobject_richcompare(PyObject *ko, PyObject *other, int op)
478{
479 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700480 PyObject *x;
481 PyObject *y;
482 PyObject *compare;
483 PyObject *answer;
484 static PyObject *zero;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200485 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700486
487 if (zero == NULL) {
488 zero = PyLong_FromLong(0);
489 if (!zero)
490 return NULL;
491 }
492
493 if (Py_TYPE(other) != &keyobject_type){
494 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
495 return NULL;
496 }
497 compare = ((keyobject *) ko)->cmp;
498 assert(compare != NULL);
499 x = ((keyobject *) ko)->object;
500 y = ((keyobject *) other)->object;
501 if (!x || !y){
502 PyErr_Format(PyExc_AttributeError, "object");
503 return NULL;
504 }
505
506 /* Call the user's comparison function and translate the 3-way
507 * result into true or false (or error).
508 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200509 stack[0] = x;
510 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200511 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200512 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700513 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200514 }
515
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700516 answer = PyObject_RichCompare(res, zero, op);
517 Py_DECREF(res);
518 return answer;
519}
520
521static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200522functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
523{
524 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700525 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200526 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700527
528 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
529 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200530 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700531 if (!object)
532 return NULL;
533 Py_INCREF(cmp);
534 object->cmp = cmp;
535 object->object = NULL;
536 return (PyObject *)object;
537}
538
539PyDoc_STRVAR(functools_cmp_to_key_doc,
540"Convert a cmp= function into a key= function.");
541
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000542/* reduce (used to be a builtin) ********************************************/
543
544static PyObject *
545functools_reduce(PyObject *self, PyObject *args)
546{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000547 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000548
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000549 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
550 return NULL;
551 if (result != NULL)
552 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000553
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000554 it = PyObject_GetIter(seq);
555 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000556 if (PyErr_ExceptionMatches(PyExc_TypeError))
557 PyErr_SetString(PyExc_TypeError,
558 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 Py_XDECREF(result);
560 return NULL;
561 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000562
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000563 if ((args = PyTuple_New(2)) == NULL)
564 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000565
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000566 for (;;) {
567 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000568
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000569 if (args->ob_refcnt > 1) {
570 Py_DECREF(args);
571 if ((args = PyTuple_New(2)) == NULL)
572 goto Fail;
573 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000574
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 op2 = PyIter_Next(it);
576 if (op2 == NULL) {
577 if (PyErr_Occurred())
578 goto Fail;
579 break;
580 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000581
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000582 if (result == NULL)
583 result = op2;
584 else {
585 PyTuple_SetItem(args, 0, result);
586 PyTuple_SetItem(args, 1, op2);
587 if ((result = PyEval_CallObject(func, args)) == NULL)
588 goto Fail;
589 }
590 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000591
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000592 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000593
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000594 if (result == NULL)
595 PyErr_SetString(PyExc_TypeError,
596 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000597
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000598 Py_DECREF(it);
599 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000600
601Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000602 Py_XDECREF(args);
603 Py_XDECREF(result);
604 Py_DECREF(it);
605 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000606}
607
608PyDoc_STRVAR(functools_reduce_doc,
609"reduce(function, sequence[, initial]) -> value\n\
610\n\
611Apply a function of two arguments cumulatively to the items of a sequence,\n\
612from left to right, so as to reduce the sequence to a single value.\n\
613For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
614((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
615of the sequence in the calculation, and serves as a default when the\n\
616sequence is empty.");
617
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300618/* lru_cache object **********************************************************/
619
620/* this object is used delimit args and keywords in the cache keys */
621static PyObject *kwd_mark = NULL;
622
623struct lru_list_elem;
624struct lru_cache_object;
625
626typedef struct lru_list_elem {
627 PyObject_HEAD
628 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300629 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300630 PyObject *key, *result;
631} lru_list_elem;
632
633static void
634lru_list_elem_dealloc(lru_list_elem *link)
635{
636 _PyObject_GC_UNTRACK(link);
637 Py_XDECREF(link->key);
638 Py_XDECREF(link->result);
639 PyObject_GC_Del(link);
640}
641
642static int
643lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
644{
645 Py_VISIT(link->key);
646 Py_VISIT(link->result);
647 return 0;
648}
649
650static int
651lru_list_elem_clear(lru_list_elem *link)
652{
653 Py_CLEAR(link->key);
654 Py_CLEAR(link->result);
655 return 0;
656}
657
658static PyTypeObject lru_list_elem_type = {
659 PyVarObject_HEAD_INIT(&PyType_Type, 0)
660 "functools._lru_list_elem", /* tp_name */
661 sizeof(lru_list_elem), /* tp_basicsize */
662 0, /* tp_itemsize */
663 /* methods */
664 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
665 0, /* tp_print */
666 0, /* tp_getattr */
667 0, /* tp_setattr */
668 0, /* tp_reserved */
669 0, /* tp_repr */
670 0, /* tp_as_number */
671 0, /* tp_as_sequence */
672 0, /* tp_as_mapping */
673 0, /* tp_hash */
674 0, /* tp_call */
675 0, /* tp_str */
676 0, /* tp_getattro */
677 0, /* tp_setattro */
678 0, /* tp_as_buffer */
679 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
680 0, /* tp_doc */
681 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
682 (inquiry)lru_list_elem_clear, /* tp_clear */
683};
684
685
686typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
687
688typedef struct lru_cache_object {
689 lru_list_elem root; /* includes PyObject_HEAD */
690 Py_ssize_t maxsize;
691 PyObject *maxsize_O;
692 PyObject *func;
693 lru_cache_ternaryfunc wrapper;
694 PyObject *cache;
695 PyObject *cache_info_type;
696 Py_ssize_t misses, hits;
697 int typed;
698 PyObject *dict;
699 int full;
700} lru_cache_object;
701
702static PyTypeObject lru_cache_type;
703
704static PyObject *
705lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
706{
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800707 PyObject *key, *keyword, *value;
708 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300709
710 /* short path, key will match args anyway, which is a tuple */
711 if (!typed && !kwds) {
712 Py_INCREF(args);
713 return args;
714 }
715
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800716 kwds_size = kwds ? PyDict_Size(kwds) : 0;
717 assert(kwds_size >= 0);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300718
719 key_size = PyTuple_GET_SIZE(args);
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800720 if (kwds_size)
721 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300722 if (typed)
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800723 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300724
725 key = PyTuple_New(key_size);
726 if (key == NULL)
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800727 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300728
729 key_pos = 0;
730 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
731 PyObject *item = PyTuple_GET_ITEM(args, pos);
732 Py_INCREF(item);
733 PyTuple_SET_ITEM(key, key_pos++, item);
734 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800735 if (kwds_size) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300736 Py_INCREF(kwd_mark);
737 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800738 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
739 Py_INCREF(keyword);
740 PyTuple_SET_ITEM(key, key_pos++, keyword);
741 Py_INCREF(value);
742 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300743 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800744 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300745 }
746 if (typed) {
747 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
748 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
749 Py_INCREF(item);
750 PyTuple_SET_ITEM(key, key_pos++, item);
751 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800752 if (kwds_size) {
753 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
754 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300755 Py_INCREF(item);
756 PyTuple_SET_ITEM(key, key_pos++, item);
757 }
758 }
759 }
760 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300761 return key;
762}
763
764static PyObject *
765uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
766{
767 PyObject *result = PyObject_Call(self->func, args, kwds);
768 if (!result)
769 return NULL;
770 self->misses++;
771 return result;
772}
773
774static PyObject *
775infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
776{
777 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300778 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300779 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
780 if (!key)
781 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300782 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500783 if (hash == -1) {
784 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300785 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500786 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300787 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300788 if (result) {
789 Py_INCREF(result);
790 self->hits++;
791 Py_DECREF(key);
792 return result;
793 }
794 if (PyErr_Occurred()) {
795 Py_DECREF(key);
796 return NULL;
797 }
798 result = PyObject_Call(self->func, args, kwds);
799 if (!result) {
800 Py_DECREF(key);
801 return NULL;
802 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300803 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300804 Py_DECREF(result);
805 Py_DECREF(key);
806 return NULL;
807 }
808 Py_DECREF(key);
809 self->misses++;
810 return result;
811}
812
813static void
814lru_cache_extricate_link(lru_list_elem *link)
815{
816 link->prev->next = link->next;
817 link->next->prev = link->prev;
818}
819
820static void
821lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
822{
823 lru_list_elem *root = &self->root;
824 lru_list_elem *last = root->prev;
825 last->next = root->prev = link;
826 link->prev = last;
827 link->next = root;
828}
829
830static PyObject *
831bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
832{
833 lru_list_elem *link;
834 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300835 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300836
837 key = lru_cache_make_key(args, kwds, self->typed);
838 if (!key)
839 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300840 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500841 if (hash == -1) {
842 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300843 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500844 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300845 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300846 if (link) {
847 lru_cache_extricate_link(link);
848 lru_cache_append_link(self, link);
849 self->hits++;
850 result = link->result;
851 Py_INCREF(result);
852 Py_DECREF(key);
853 return result;
854 }
855 if (PyErr_Occurred()) {
856 Py_DECREF(key);
857 return NULL;
858 }
859 result = PyObject_Call(self->func, args, kwds);
860 if (!result) {
861 Py_DECREF(key);
862 return NULL;
863 }
864 if (self->full && self->root.next != &self->root) {
865 /* Use the oldest item to store the new key and result. */
Serhiy Storchaka67796522017-01-12 18:34:33 +0200866 PyObject *oldkey, *oldresult, *popresult;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300867 /* Extricate the oldest item. */
868 link = self->root.next;
869 lru_cache_extricate_link(link);
870 /* Remove it from the cache.
871 The cache dict holds one reference to the link,
872 and the linked list holds yet one reference to it. */
Serhiy Storchaka42e1ea92017-01-12 19:12:21 +0200873 popresult = _PyDict_Pop_KnownHash(self->cache,
Serhiy Storchaka67796522017-01-12 18:34:33 +0200874 link->key, link->hash,
875 Py_None);
876 if (popresult == Py_None) {
877 /* Getting here means that this same key was added to the
878 cache while the lock was released. Since the link
879 update is already done, we need only return the
880 computed result and update the count of misses. */
881 Py_DECREF(popresult);
882 Py_DECREF(link);
883 Py_DECREF(key);
884 }
885 else if (popresult == NULL) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300886 lru_cache_append_link(self, link);
887 Py_DECREF(key);
888 Py_DECREF(result);
889 return NULL;
890 }
Serhiy Storchaka67796522017-01-12 18:34:33 +0200891 else {
892 Py_DECREF(popresult);
893 /* Keep a reference to the old key and old result to
894 prevent their ref counts from going to zero during the
895 update. That will prevent potentially arbitrary object
896 clean-up code (i.e. __del__) from running while we're
897 still adjusting the links. */
898 oldkey = link->key;
899 oldresult = link->result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300900
Serhiy Storchaka67796522017-01-12 18:34:33 +0200901 link->hash = hash;
902 link->key = key;
903 link->result = result;
904 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
905 hash) < 0) {
906 Py_DECREF(link);
907 Py_DECREF(oldkey);
908 Py_DECREF(oldresult);
909 return NULL;
910 }
911 lru_cache_append_link(self, link);
912 Py_INCREF(result); /* for return */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300913 Py_DECREF(oldkey);
914 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300915 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300916 } else {
917 /* Put result in a new link at the front of the queue. */
918 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
919 &lru_list_elem_type);
920 if (link == NULL) {
921 Py_DECREF(key);
922 Py_DECREF(result);
923 return NULL;
924 }
925
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300926 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300927 link->key = key;
928 link->result = result;
929 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300930 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
931 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300932 Py_DECREF(link);
933 return NULL;
934 }
935 lru_cache_append_link(self, link);
936 Py_INCREF(result); /* for return */
937 self->full = (PyDict_Size(self->cache) >= self->maxsize);
938 }
939 self->misses++;
940 return result;
941}
942
943static PyObject *
944lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
945{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300946 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300947 int typed;
948 lru_cache_object *obj;
949 Py_ssize_t maxsize;
950 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
951 static char *keywords[] = {"user_function", "maxsize", "typed",
952 "cache_info_type", NULL};
953
954 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
955 &func, &maxsize_O, &typed,
956 &cache_info_type)) {
957 return NULL;
958 }
959
960 if (!PyCallable_Check(func)) {
961 PyErr_SetString(PyExc_TypeError,
962 "the first argument must be callable");
963 return NULL;
964 }
965
966 /* select the caching function, and make/inc maxsize_O */
967 if (maxsize_O == Py_None) {
968 wrapper = infinite_lru_cache_wrapper;
969 /* use this only to initialize lru_cache_object attribute maxsize */
970 maxsize = -1;
971 } else if (PyIndex_Check(maxsize_O)) {
972 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
973 if (maxsize == -1 && PyErr_Occurred())
974 return NULL;
975 if (maxsize == 0)
976 wrapper = uncached_lru_cache_wrapper;
977 else
978 wrapper = bounded_lru_cache_wrapper;
979 } else {
980 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
981 return NULL;
982 }
983
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300984 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300985 return NULL;
986
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300987 obj = (lru_cache_object *)type->tp_alloc(type, 0);
988 if (obj == NULL) {
989 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300990 return NULL;
991 }
992
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300993 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300994 obj->root.prev = &obj->root;
995 obj->root.next = &obj->root;
996 obj->maxsize = maxsize;
997 Py_INCREF(maxsize_O);
998 obj->maxsize_O = maxsize_O;
999 Py_INCREF(func);
1000 obj->func = func;
1001 obj->wrapper = wrapper;
1002 obj->misses = obj->hits = 0;
1003 obj->typed = typed;
1004 Py_INCREF(cache_info_type);
1005 obj->cache_info_type = cache_info_type;
1006
1007 return (PyObject *)obj;
1008}
1009
1010static lru_list_elem *
1011lru_cache_unlink_list(lru_cache_object *self)
1012{
1013 lru_list_elem *root = &self->root;
1014 lru_list_elem *link = root->next;
1015 if (link == root)
1016 return NULL;
1017 root->prev->next = NULL;
1018 root->next = root->prev = root;
1019 return link;
1020}
1021
1022static void
1023lru_cache_clear_list(lru_list_elem *link)
1024{
1025 while (link != NULL) {
1026 lru_list_elem *next = link->next;
1027 Py_DECREF(link);
1028 link = next;
1029 }
1030}
1031
1032static void
1033lru_cache_dealloc(lru_cache_object *obj)
1034{
1035 lru_list_elem *list = lru_cache_unlink_list(obj);
1036 Py_XDECREF(obj->maxsize_O);
1037 Py_XDECREF(obj->func);
1038 Py_XDECREF(obj->cache);
1039 Py_XDECREF(obj->dict);
1040 Py_XDECREF(obj->cache_info_type);
1041 lru_cache_clear_list(list);
1042 Py_TYPE(obj)->tp_free(obj);
1043}
1044
1045static PyObject *
1046lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1047{
1048 return self->wrapper(self, args, kwds);
1049}
1050
1051static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001052lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1053{
1054 if (obj == Py_None || obj == NULL) {
1055 Py_INCREF(self);
1056 return self;
1057 }
1058 return PyMethod_New(self, obj);
1059}
1060
1061static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001062lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1063{
1064 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1065 self->hits, self->misses, self->maxsize_O,
1066 PyDict_Size(self->cache));
1067}
1068
1069static PyObject *
1070lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1071{
1072 lru_list_elem *list = lru_cache_unlink_list(self);
1073 self->hits = self->misses = 0;
1074 self->full = 0;
1075 PyDict_Clear(self->cache);
1076 lru_cache_clear_list(list);
1077 Py_RETURN_NONE;
1078}
1079
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001080static PyObject *
1081lru_cache_reduce(PyObject *self, PyObject *unused)
1082{
1083 return PyObject_GetAttrString(self, "__qualname__");
1084}
1085
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001086static PyObject *
1087lru_cache_copy(PyObject *self, PyObject *unused)
1088{
1089 Py_INCREF(self);
1090 return self;
1091}
1092
1093static PyObject *
1094lru_cache_deepcopy(PyObject *self, PyObject *unused)
1095{
1096 Py_INCREF(self);
1097 return self;
1098}
1099
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001100static int
1101lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1102{
1103 lru_list_elem *link = self->root.next;
1104 while (link != &self->root) {
1105 lru_list_elem *next = link->next;
1106 Py_VISIT(link);
1107 link = next;
1108 }
1109 Py_VISIT(self->maxsize_O);
1110 Py_VISIT(self->func);
1111 Py_VISIT(self->cache);
1112 Py_VISIT(self->cache_info_type);
1113 Py_VISIT(self->dict);
1114 return 0;
1115}
1116
1117static int
1118lru_cache_tp_clear(lru_cache_object *self)
1119{
1120 lru_list_elem *list = lru_cache_unlink_list(self);
1121 Py_CLEAR(self->maxsize_O);
1122 Py_CLEAR(self->func);
1123 Py_CLEAR(self->cache);
1124 Py_CLEAR(self->cache_info_type);
1125 Py_CLEAR(self->dict);
1126 lru_cache_clear_list(list);
1127 return 0;
1128}
1129
1130
1131PyDoc_STRVAR(lru_cache_doc,
1132"Create a cached callable that wraps another function.\n\
1133\n\
1134user_function: the function being cached\n\
1135\n\
1136maxsize: 0 for no caching\n\
1137 None for unlimited cache size\n\
1138 n for a bounded cache\n\
1139\n\
1140typed: False cache f(3) and f(3.0) as identical calls\n\
1141 True cache f(3) and f(3.0) as distinct calls\n\
1142\n\
1143cache_info_type: namedtuple class with the fields:\n\
1144 hits misses currsize maxsize\n"
1145);
1146
1147static PyMethodDef lru_cache_methods[] = {
1148 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1149 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001150 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001151 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1152 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001153 {NULL}
1154};
1155
1156static PyGetSetDef lru_cache_getsetlist[] = {
1157 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1158 {NULL}
1159};
1160
1161static PyTypeObject lru_cache_type = {
1162 PyVarObject_HEAD_INIT(NULL, 0)
1163 "functools._lru_cache_wrapper", /* tp_name */
1164 sizeof(lru_cache_object), /* tp_basicsize */
1165 0, /* tp_itemsize */
1166 /* methods */
1167 (destructor)lru_cache_dealloc, /* tp_dealloc */
1168 0, /* tp_print */
1169 0, /* tp_getattr */
1170 0, /* tp_setattr */
1171 0, /* tp_reserved */
1172 0, /* tp_repr */
1173 0, /* tp_as_number */
1174 0, /* tp_as_sequence */
1175 0, /* tp_as_mapping */
1176 0, /* tp_hash */
1177 (ternaryfunc)lru_cache_call, /* tp_call */
1178 0, /* tp_str */
1179 0, /* tp_getattro */
1180 0, /* tp_setattro */
1181 0, /* tp_as_buffer */
1182 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1183 /* tp_flags */
1184 lru_cache_doc, /* tp_doc */
1185 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1186 (inquiry)lru_cache_tp_clear, /* tp_clear */
1187 0, /* tp_richcompare */
1188 0, /* tp_weaklistoffset */
1189 0, /* tp_iter */
1190 0, /* tp_iternext */
1191 lru_cache_methods, /* tp_methods */
1192 0, /* tp_members */
1193 lru_cache_getsetlist, /* tp_getset */
1194 0, /* tp_base */
1195 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001196 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001197 0, /* tp_descr_set */
1198 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1199 0, /* tp_init */
1200 0, /* tp_alloc */
1201 lru_cache_new, /* tp_new */
1202};
1203
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001204/* module level code ********************************************************/
1205
1206PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001207"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001208
1209static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001210 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001211 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1212 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001213 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001214};
1215
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001216static void
1217module_free(void *m)
1218{
1219 Py_CLEAR(kwd_mark);
1220}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001221
1222static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001223 PyModuleDef_HEAD_INIT,
1224 "_functools",
1225 module_doc,
1226 -1,
1227 module_methods,
1228 NULL,
1229 NULL,
1230 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001231 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001232};
1233
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001234PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001235PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001236{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001237 int i;
1238 PyObject *m;
1239 char *name;
1240 PyTypeObject *typelist[] = {
1241 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001242 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001243 NULL
1244 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001245
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001246 m = PyModule_Create(&_functoolsmodule);
1247 if (m == NULL)
1248 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001249
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001250 kwd_mark = PyObject_CallObject((PyObject *)&PyBaseObject_Type, NULL);
1251 if (!kwd_mark) {
1252 Py_DECREF(m);
1253 return NULL;
1254 }
1255
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001256 for (i=0 ; typelist[i] != NULL ; i++) {
1257 if (PyType_Ready(typelist[i]) < 0) {
1258 Py_DECREF(m);
1259 return NULL;
1260 }
1261 name = strchr(typelist[i]->tp_name, '.');
1262 assert (name != NULL);
1263 Py_INCREF(typelist[i]);
1264 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1265 }
1266 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001267}