blob: 22e8088890baac1cfe444096b58763b0b1ad8aa2 [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;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000131
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 assert (PyCallable_Check(pto->fn));
133 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200134 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000135
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 if (PyTuple_GET_SIZE(pto->args) == 0) {
137 argappl = args;
138 Py_INCREF(args);
139 } else if (PyTuple_GET_SIZE(args) == 0) {
140 argappl = pto->args;
141 Py_INCREF(pto->args);
142 } else {
143 argappl = PySequence_Concat(pto->args, args);
144 if (argappl == NULL)
145 return NULL;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200146 assert(PyTuple_Check(argappl));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000148
Serhiy Storchaka38741282016-02-02 18:45:17 +0200149 if (PyDict_Size(pto->kw) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000150 kwappl = kw;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200151 Py_XINCREF(kwappl);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000152 } else {
153 kwappl = PyDict_Copy(pto->kw);
154 if (kwappl == NULL) {
155 Py_DECREF(argappl);
156 return NULL;
157 }
158 if (kw != NULL) {
159 if (PyDict_Merge(kwappl, kw, 1) != 0) {
160 Py_DECREF(argappl);
161 Py_DECREF(kwappl);
162 return NULL;
163 }
164 }
165 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000166
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 ret = PyObject_Call(pto->fn, argappl, kwappl);
168 Py_DECREF(argappl);
169 Py_XDECREF(kwappl);
170 return ret;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000171}
172
173static int
174partial_traverse(partialobject *pto, visitproc visit, void *arg)
175{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 Py_VISIT(pto->fn);
177 Py_VISIT(pto->args);
178 Py_VISIT(pto->kw);
179 Py_VISIT(pto->dict);
180 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000181}
182
183PyDoc_STRVAR(partial_doc,
184"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000185 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000186
187#define OFF(x) offsetof(partialobject, x)
188static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 {"func", T_OBJECT, OFF(fn), READONLY,
190 "function object to use in future partial calls"},
191 {"args", T_OBJECT, OFF(args), READONLY,
192 "tuple of arguments to future partial calls"},
193 {"keywords", T_OBJECT, OFF(kw), READONLY,
194 "dictionary of keyword arguments to future partial calls"},
195 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000196};
197
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000198static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500199 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000200 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000201};
202
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000203static PyObject *
204partial_repr(partialobject *pto)
205{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300206 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000207 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000208 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200209 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300210 int status;
211
212 status = Py_ReprEnter((PyObject *)pto);
213 if (status != 0) {
214 if (status < 0)
215 return NULL;
216 return PyUnicode_FromFormat("%s(...)", Py_TYPE(pto)->tp_name);
217 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000218
219 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300220 if (arglist == NULL)
221 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000222 /* Pack positional arguments */
223 assert (PyTuple_Check(pto->args));
224 n = PyTuple_GET_SIZE(pto->args);
225 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300226 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
227 PyTuple_GET_ITEM(pto->args, i)));
228 if (arglist == NULL)
229 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000230 }
231 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200232 assert (PyDict_Check(pto->kw));
233 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300234 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %U=%R", arglist,
235 key, value));
236 if (arglist == NULL)
237 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000238 }
239 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
240 pto->fn, arglist);
241 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300242
243 done:
244 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000245 return result;
246}
247
Jack Diederiche0cbd692009-04-01 04:27:09 +0000248/* Pickle strategy:
249 __reduce__ by itself doesn't support getting kwargs in the unpickle
250 operation so we define a __setstate__ that replaces all the information
251 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200252 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000253 */
254
Antoine Pitrou69f71142009-05-24 21:25:49 +0000255static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000256partial_reduce(partialobject *pto, PyObject *unused)
257{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000258 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
259 pto->args, pto->kw,
260 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000261}
262
Antoine Pitrou69f71142009-05-24 21:25:49 +0000263static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200264partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000265{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200267
268 if (!PyTuple_Check(state) ||
269 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
270 !PyCallable_Check(fn) ||
271 !PyTuple_Check(fnargs) ||
272 (kw != Py_None && !PyDict_Check(kw)))
273 {
274 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200277
278 if(!PyTuple_CheckExact(fnargs))
279 fnargs = PySequence_Tuple(fnargs);
280 else
281 Py_INCREF(fnargs);
282 if (fnargs == NULL)
283 return NULL;
284
285 if (kw == Py_None)
286 kw = PyDict_New();
287 else if(!PyDict_CheckExact(kw))
288 kw = PyDict_Copy(kw);
289 else
290 Py_INCREF(kw);
291 if (kw == NULL) {
292 Py_DECREF(fnargs);
293 return NULL;
294 }
295
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296 Py_INCREF(fn);
Serhiy Storchaka38741282016-02-02 18:45:17 +0200297 if (dict == Py_None)
298 dict = NULL;
299 else
300 Py_INCREF(dict);
301
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300302 Py_SETREF(pto->fn, fn);
303 Py_SETREF(pto->args, fnargs);
304 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300305 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000307}
308
309static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000310 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200311 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000313};
314
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000315static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000316 PyVarObject_HEAD_INIT(NULL, 0)
317 "functools.partial", /* tp_name */
318 sizeof(partialobject), /* tp_basicsize */
319 0, /* tp_itemsize */
320 /* methods */
321 (destructor)partial_dealloc, /* tp_dealloc */
322 0, /* tp_print */
323 0, /* tp_getattr */
324 0, /* tp_setattr */
325 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000326 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 0, /* tp_as_number */
328 0, /* tp_as_sequence */
329 0, /* tp_as_mapping */
330 0, /* tp_hash */
331 (ternaryfunc)partial_call, /* tp_call */
332 0, /* tp_str */
333 PyObject_GenericGetAttr, /* tp_getattro */
334 PyObject_GenericSetAttr, /* tp_setattro */
335 0, /* tp_as_buffer */
336 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
337 Py_TPFLAGS_BASETYPE, /* tp_flags */
338 partial_doc, /* tp_doc */
339 (traverseproc)partial_traverse, /* tp_traverse */
340 0, /* tp_clear */
341 0, /* tp_richcompare */
342 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
343 0, /* tp_iter */
344 0, /* tp_iternext */
345 partial_methods, /* tp_methods */
346 partial_memberlist, /* tp_members */
347 partial_getsetlist, /* tp_getset */
348 0, /* tp_base */
349 0, /* tp_dict */
350 0, /* tp_descr_get */
351 0, /* tp_descr_set */
352 offsetof(partialobject, dict), /* tp_dictoffset */
353 0, /* tp_init */
354 0, /* tp_alloc */
355 partial_new, /* tp_new */
356 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000357};
358
359
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700360/* cmp_to_key ***************************************************************/
361
362typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200363 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700364 PyObject *cmp;
365 PyObject *object;
366} keyobject;
367
368static void
369keyobject_dealloc(keyobject *ko)
370{
371 Py_DECREF(ko->cmp);
372 Py_XDECREF(ko->object);
373 PyObject_FREE(ko);
374}
375
376static int
377keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
378{
379 Py_VISIT(ko->cmp);
380 if (ko->object)
381 Py_VISIT(ko->object);
382 return 0;
383}
384
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500385static int
386keyobject_clear(keyobject *ko)
387{
388 Py_CLEAR(ko->cmp);
389 if (ko->object)
390 Py_CLEAR(ko->object);
391 return 0;
392}
393
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700394static PyMemberDef keyobject_members[] = {
395 {"obj", T_OBJECT,
396 offsetof(keyobject, object), 0,
397 PyDoc_STR("Value wrapped by a key function.")},
398 {NULL}
399};
400
401static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700402keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700403
404static PyObject *
405keyobject_richcompare(PyObject *ko, PyObject *other, int op);
406
407static PyTypeObject keyobject_type = {
408 PyVarObject_HEAD_INIT(&PyType_Type, 0)
409 "functools.KeyWrapper", /* tp_name */
410 sizeof(keyobject), /* tp_basicsize */
411 0, /* tp_itemsize */
412 /* methods */
413 (destructor)keyobject_dealloc, /* tp_dealloc */
414 0, /* tp_print */
415 0, /* tp_getattr */
416 0, /* tp_setattr */
417 0, /* tp_reserved */
418 0, /* tp_repr */
419 0, /* tp_as_number */
420 0, /* tp_as_sequence */
421 0, /* tp_as_mapping */
422 0, /* tp_hash */
423 (ternaryfunc)keyobject_call, /* tp_call */
424 0, /* tp_str */
425 PyObject_GenericGetAttr, /* tp_getattro */
426 0, /* tp_setattro */
427 0, /* tp_as_buffer */
428 Py_TPFLAGS_DEFAULT, /* tp_flags */
429 0, /* tp_doc */
430 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500431 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700432 keyobject_richcompare, /* tp_richcompare */
433 0, /* tp_weaklistoffset */
434 0, /* tp_iter */
435 0, /* tp_iternext */
436 0, /* tp_methods */
437 keyobject_members, /* tp_members */
438 0, /* tp_getset */
439};
440
441static PyObject *
442keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
443{
444 PyObject *object;
445 keyobject *result;
446 static char *kwargs[] = {"obj", NULL};
447
448 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
449 return NULL;
450 result = PyObject_New(keyobject, &keyobject_type);
451 if (!result)
452 return NULL;
453 Py_INCREF(ko->cmp);
454 result->cmp = ko->cmp;
455 Py_INCREF(object);
456 result->object = object;
457 return (PyObject *)result;
458}
459
460static PyObject *
461keyobject_richcompare(PyObject *ko, PyObject *other, int op)
462{
463 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700464 PyObject *x;
465 PyObject *y;
466 PyObject *compare;
467 PyObject *answer;
468 static PyObject *zero;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200469 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700470
471 if (zero == NULL) {
472 zero = PyLong_FromLong(0);
473 if (!zero)
474 return NULL;
475 }
476
477 if (Py_TYPE(other) != &keyobject_type){
478 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
479 return NULL;
480 }
481 compare = ((keyobject *) ko)->cmp;
482 assert(compare != NULL);
483 x = ((keyobject *) ko)->object;
484 y = ((keyobject *) other)->object;
485 if (!x || !y){
486 PyErr_Format(PyExc_AttributeError, "object");
487 return NULL;
488 }
489
490 /* Call the user's comparison function and translate the 3-way
491 * result into true or false (or error).
492 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200493 stack[0] = x;
494 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200495 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200496 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700497 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200498 }
499
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700500 answer = PyObject_RichCompare(res, zero, op);
501 Py_DECREF(res);
502 return answer;
503}
504
505static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200506functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
507{
508 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700509 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200510 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700511
512 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
513 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200514 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700515 if (!object)
516 return NULL;
517 Py_INCREF(cmp);
518 object->cmp = cmp;
519 object->object = NULL;
520 return (PyObject *)object;
521}
522
523PyDoc_STRVAR(functools_cmp_to_key_doc,
524"Convert a cmp= function into a key= function.");
525
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000526/* reduce (used to be a builtin) ********************************************/
527
528static PyObject *
529functools_reduce(PyObject *self, PyObject *args)
530{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000531 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000532
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000533 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
534 return NULL;
535 if (result != NULL)
536 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000537
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000538 it = PyObject_GetIter(seq);
539 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000540 if (PyErr_ExceptionMatches(PyExc_TypeError))
541 PyErr_SetString(PyExc_TypeError,
542 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000543 Py_XDECREF(result);
544 return NULL;
545 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000546
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000547 if ((args = PyTuple_New(2)) == NULL)
548 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000549
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000550 for (;;) {
551 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000552
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000553 if (args->ob_refcnt > 1) {
554 Py_DECREF(args);
555 if ((args = PyTuple_New(2)) == NULL)
556 goto Fail;
557 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000558
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 op2 = PyIter_Next(it);
560 if (op2 == NULL) {
561 if (PyErr_Occurred())
562 goto Fail;
563 break;
564 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000565
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000566 if (result == NULL)
567 result = op2;
568 else {
569 PyTuple_SetItem(args, 0, result);
570 PyTuple_SetItem(args, 1, op2);
571 if ((result = PyEval_CallObject(func, args)) == NULL)
572 goto Fail;
573 }
574 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000575
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000576 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000577
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000578 if (result == NULL)
579 PyErr_SetString(PyExc_TypeError,
580 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000581
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000582 Py_DECREF(it);
583 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000584
585Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000586 Py_XDECREF(args);
587 Py_XDECREF(result);
588 Py_DECREF(it);
589 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000590}
591
592PyDoc_STRVAR(functools_reduce_doc,
593"reduce(function, sequence[, initial]) -> value\n\
594\n\
595Apply a function of two arguments cumulatively to the items of a sequence,\n\
596from left to right, so as to reduce the sequence to a single value.\n\
597For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
598((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
599of the sequence in the calculation, and serves as a default when the\n\
600sequence is empty.");
601
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300602/* lru_cache object **********************************************************/
603
604/* this object is used delimit args and keywords in the cache keys */
605static PyObject *kwd_mark = NULL;
606
607struct lru_list_elem;
608struct lru_cache_object;
609
610typedef struct lru_list_elem {
611 PyObject_HEAD
612 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300613 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300614 PyObject *key, *result;
615} lru_list_elem;
616
617static void
618lru_list_elem_dealloc(lru_list_elem *link)
619{
620 _PyObject_GC_UNTRACK(link);
621 Py_XDECREF(link->key);
622 Py_XDECREF(link->result);
623 PyObject_GC_Del(link);
624}
625
626static int
627lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
628{
629 Py_VISIT(link->key);
630 Py_VISIT(link->result);
631 return 0;
632}
633
634static int
635lru_list_elem_clear(lru_list_elem *link)
636{
637 Py_CLEAR(link->key);
638 Py_CLEAR(link->result);
639 return 0;
640}
641
642static PyTypeObject lru_list_elem_type = {
643 PyVarObject_HEAD_INIT(&PyType_Type, 0)
644 "functools._lru_list_elem", /* tp_name */
645 sizeof(lru_list_elem), /* tp_basicsize */
646 0, /* tp_itemsize */
647 /* methods */
648 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
649 0, /* tp_print */
650 0, /* tp_getattr */
651 0, /* tp_setattr */
652 0, /* tp_reserved */
653 0, /* tp_repr */
654 0, /* tp_as_number */
655 0, /* tp_as_sequence */
656 0, /* tp_as_mapping */
657 0, /* tp_hash */
658 0, /* tp_call */
659 0, /* tp_str */
660 0, /* tp_getattro */
661 0, /* tp_setattro */
662 0, /* tp_as_buffer */
663 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
664 0, /* tp_doc */
665 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
666 (inquiry)lru_list_elem_clear, /* tp_clear */
667};
668
669
670typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
671
672typedef struct lru_cache_object {
673 lru_list_elem root; /* includes PyObject_HEAD */
674 Py_ssize_t maxsize;
675 PyObject *maxsize_O;
676 PyObject *func;
677 lru_cache_ternaryfunc wrapper;
678 PyObject *cache;
679 PyObject *cache_info_type;
680 Py_ssize_t misses, hits;
681 int typed;
682 PyObject *dict;
683 int full;
684} lru_cache_object;
685
686static PyTypeObject lru_cache_type;
687
688static PyObject *
689lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
690{
691 PyObject *key, *sorted_items;
692 Py_ssize_t key_size, pos, key_pos;
693
694 /* short path, key will match args anyway, which is a tuple */
695 if (!typed && !kwds) {
696 Py_INCREF(args);
697 return args;
698 }
699
700 if (kwds && PyDict_Size(kwds) > 0) {
701 sorted_items = PyDict_Items(kwds);
702 if (!sorted_items)
703 return NULL;
704 if (PyList_Sort(sorted_items) < 0) {
705 Py_DECREF(sorted_items);
706 return NULL;
707 }
708 } else
709 sorted_items = NULL;
710
711 key_size = PyTuple_GET_SIZE(args);
712 if (sorted_items)
713 key_size += PyList_GET_SIZE(sorted_items);
714 if (typed)
715 key_size *= 2;
716 if (sorted_items)
717 key_size++;
718
719 key = PyTuple_New(key_size);
720 if (key == NULL)
721 goto done;
722
723 key_pos = 0;
724 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
725 PyObject *item = PyTuple_GET_ITEM(args, pos);
726 Py_INCREF(item);
727 PyTuple_SET_ITEM(key, key_pos++, item);
728 }
729 if (sorted_items) {
730 Py_INCREF(kwd_mark);
731 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
732 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
733 PyObject *item = PyList_GET_ITEM(sorted_items, pos);
734 Py_INCREF(item);
735 PyTuple_SET_ITEM(key, key_pos++, item);
736 }
737 }
738 if (typed) {
739 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
740 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
741 Py_INCREF(item);
742 PyTuple_SET_ITEM(key, key_pos++, item);
743 }
744 if (sorted_items) {
745 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
746 PyObject *tp_items = PyList_GET_ITEM(sorted_items, pos);
747 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(tp_items, 1));
748 Py_INCREF(item);
749 PyTuple_SET_ITEM(key, key_pos++, item);
750 }
751 }
752 }
753 assert(key_pos == key_size);
754
755done:
756 if (sorted_items)
757 Py_DECREF(sorted_items);
758 return key;
759}
760
761static PyObject *
762uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
763{
764 PyObject *result = PyObject_Call(self->func, args, kwds);
765 if (!result)
766 return NULL;
767 self->misses++;
768 return result;
769}
770
771static PyObject *
772infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
773{
774 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300775 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300776 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
777 if (!key)
778 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300779 hash = PyObject_Hash(key);
780 if (hash == -1)
781 return NULL;
782 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300783 if (result) {
784 Py_INCREF(result);
785 self->hits++;
786 Py_DECREF(key);
787 return result;
788 }
789 if (PyErr_Occurred()) {
790 Py_DECREF(key);
791 return NULL;
792 }
793 result = PyObject_Call(self->func, args, kwds);
794 if (!result) {
795 Py_DECREF(key);
796 return NULL;
797 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300798 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300799 Py_DECREF(result);
800 Py_DECREF(key);
801 return NULL;
802 }
803 Py_DECREF(key);
804 self->misses++;
805 return result;
806}
807
808static void
809lru_cache_extricate_link(lru_list_elem *link)
810{
811 link->prev->next = link->next;
812 link->next->prev = link->prev;
813}
814
815static void
816lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
817{
818 lru_list_elem *root = &self->root;
819 lru_list_elem *last = root->prev;
820 last->next = root->prev = link;
821 link->prev = last;
822 link->next = root;
823}
824
825static PyObject *
826bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
827{
828 lru_list_elem *link;
829 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300830 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300831
832 key = lru_cache_make_key(args, kwds, self->typed);
833 if (!key)
834 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300835 hash = PyObject_Hash(key);
836 if (hash == -1)
837 return NULL;
838 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300839 if (link) {
840 lru_cache_extricate_link(link);
841 lru_cache_append_link(self, link);
842 self->hits++;
843 result = link->result;
844 Py_INCREF(result);
845 Py_DECREF(key);
846 return result;
847 }
848 if (PyErr_Occurred()) {
849 Py_DECREF(key);
850 return NULL;
851 }
852 result = PyObject_Call(self->func, args, kwds);
853 if (!result) {
854 Py_DECREF(key);
855 return NULL;
856 }
857 if (self->full && self->root.next != &self->root) {
858 /* Use the oldest item to store the new key and result. */
859 PyObject *oldkey, *oldresult;
860 /* Extricate the oldest item. */
861 link = self->root.next;
862 lru_cache_extricate_link(link);
863 /* Remove it from the cache.
864 The cache dict holds one reference to the link,
865 and the linked list holds yet one reference to it. */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300866 if (_PyDict_DelItem_KnownHash(self->cache, link->key,
867 link->hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300868 lru_cache_append_link(self, link);
869 Py_DECREF(key);
870 Py_DECREF(result);
871 return NULL;
872 }
873 /* Keep a reference to the old key and old result to
874 prevent their ref counts from going to zero during the
875 update. That will prevent potentially arbitrary object
876 clean-up code (i.e. __del__) from running while we're
877 still adjusting the links. */
878 oldkey = link->key;
879 oldresult = link->result;
880
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300881 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300882 link->key = key;
883 link->result = result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300884 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
885 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300886 Py_DECREF(link);
887 Py_DECREF(oldkey);
888 Py_DECREF(oldresult);
889 return NULL;
890 }
891 lru_cache_append_link(self, link);
892 Py_INCREF(result); /* for return */
893 Py_DECREF(oldkey);
894 Py_DECREF(oldresult);
895 } else {
896 /* Put result in a new link at the front of the queue. */
897 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
898 &lru_list_elem_type);
899 if (link == NULL) {
900 Py_DECREF(key);
901 Py_DECREF(result);
902 return NULL;
903 }
904
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300905 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300906 link->key = key;
907 link->result = result;
908 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300909 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
910 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300911 Py_DECREF(link);
912 return NULL;
913 }
914 lru_cache_append_link(self, link);
915 Py_INCREF(result); /* for return */
916 self->full = (PyDict_Size(self->cache) >= self->maxsize);
917 }
918 self->misses++;
919 return result;
920}
921
922static PyObject *
923lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
924{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300925 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300926 int typed;
927 lru_cache_object *obj;
928 Py_ssize_t maxsize;
929 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
930 static char *keywords[] = {"user_function", "maxsize", "typed",
931 "cache_info_type", NULL};
932
933 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
934 &func, &maxsize_O, &typed,
935 &cache_info_type)) {
936 return NULL;
937 }
938
939 if (!PyCallable_Check(func)) {
940 PyErr_SetString(PyExc_TypeError,
941 "the first argument must be callable");
942 return NULL;
943 }
944
945 /* select the caching function, and make/inc maxsize_O */
946 if (maxsize_O == Py_None) {
947 wrapper = infinite_lru_cache_wrapper;
948 /* use this only to initialize lru_cache_object attribute maxsize */
949 maxsize = -1;
950 } else if (PyIndex_Check(maxsize_O)) {
951 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
952 if (maxsize == -1 && PyErr_Occurred())
953 return NULL;
954 if (maxsize == 0)
955 wrapper = uncached_lru_cache_wrapper;
956 else
957 wrapper = bounded_lru_cache_wrapper;
958 } else {
959 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
960 return NULL;
961 }
962
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300963 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300964 return NULL;
965
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300966 obj = (lru_cache_object *)type->tp_alloc(type, 0);
967 if (obj == NULL) {
968 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300969 return NULL;
970 }
971
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300972 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300973 obj->root.prev = &obj->root;
974 obj->root.next = &obj->root;
975 obj->maxsize = maxsize;
976 Py_INCREF(maxsize_O);
977 obj->maxsize_O = maxsize_O;
978 Py_INCREF(func);
979 obj->func = func;
980 obj->wrapper = wrapper;
981 obj->misses = obj->hits = 0;
982 obj->typed = typed;
983 Py_INCREF(cache_info_type);
984 obj->cache_info_type = cache_info_type;
985
986 return (PyObject *)obj;
987}
988
989static lru_list_elem *
990lru_cache_unlink_list(lru_cache_object *self)
991{
992 lru_list_elem *root = &self->root;
993 lru_list_elem *link = root->next;
994 if (link == root)
995 return NULL;
996 root->prev->next = NULL;
997 root->next = root->prev = root;
998 return link;
999}
1000
1001static void
1002lru_cache_clear_list(lru_list_elem *link)
1003{
1004 while (link != NULL) {
1005 lru_list_elem *next = link->next;
1006 Py_DECREF(link);
1007 link = next;
1008 }
1009}
1010
1011static void
1012lru_cache_dealloc(lru_cache_object *obj)
1013{
1014 lru_list_elem *list = lru_cache_unlink_list(obj);
1015 Py_XDECREF(obj->maxsize_O);
1016 Py_XDECREF(obj->func);
1017 Py_XDECREF(obj->cache);
1018 Py_XDECREF(obj->dict);
1019 Py_XDECREF(obj->cache_info_type);
1020 lru_cache_clear_list(list);
1021 Py_TYPE(obj)->tp_free(obj);
1022}
1023
1024static PyObject *
1025lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1026{
1027 return self->wrapper(self, args, kwds);
1028}
1029
1030static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001031lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1032{
1033 if (obj == Py_None || obj == NULL) {
1034 Py_INCREF(self);
1035 return self;
1036 }
1037 return PyMethod_New(self, obj);
1038}
1039
1040static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001041lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1042{
1043 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1044 self->hits, self->misses, self->maxsize_O,
1045 PyDict_Size(self->cache));
1046}
1047
1048static PyObject *
1049lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1050{
1051 lru_list_elem *list = lru_cache_unlink_list(self);
1052 self->hits = self->misses = 0;
1053 self->full = 0;
1054 PyDict_Clear(self->cache);
1055 lru_cache_clear_list(list);
1056 Py_RETURN_NONE;
1057}
1058
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001059static PyObject *
1060lru_cache_reduce(PyObject *self, PyObject *unused)
1061{
1062 return PyObject_GetAttrString(self, "__qualname__");
1063}
1064
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001065static PyObject *
1066lru_cache_copy(PyObject *self, PyObject *unused)
1067{
1068 Py_INCREF(self);
1069 return self;
1070}
1071
1072static PyObject *
1073lru_cache_deepcopy(PyObject *self, PyObject *unused)
1074{
1075 Py_INCREF(self);
1076 return self;
1077}
1078
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001079static int
1080lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1081{
1082 lru_list_elem *link = self->root.next;
1083 while (link != &self->root) {
1084 lru_list_elem *next = link->next;
1085 Py_VISIT(link);
1086 link = next;
1087 }
1088 Py_VISIT(self->maxsize_O);
1089 Py_VISIT(self->func);
1090 Py_VISIT(self->cache);
1091 Py_VISIT(self->cache_info_type);
1092 Py_VISIT(self->dict);
1093 return 0;
1094}
1095
1096static int
1097lru_cache_tp_clear(lru_cache_object *self)
1098{
1099 lru_list_elem *list = lru_cache_unlink_list(self);
1100 Py_CLEAR(self->maxsize_O);
1101 Py_CLEAR(self->func);
1102 Py_CLEAR(self->cache);
1103 Py_CLEAR(self->cache_info_type);
1104 Py_CLEAR(self->dict);
1105 lru_cache_clear_list(list);
1106 return 0;
1107}
1108
1109
1110PyDoc_STRVAR(lru_cache_doc,
1111"Create a cached callable that wraps another function.\n\
1112\n\
1113user_function: the function being cached\n\
1114\n\
1115maxsize: 0 for no caching\n\
1116 None for unlimited cache size\n\
1117 n for a bounded cache\n\
1118\n\
1119typed: False cache f(3) and f(3.0) as identical calls\n\
1120 True cache f(3) and f(3.0) as distinct calls\n\
1121\n\
1122cache_info_type: namedtuple class with the fields:\n\
1123 hits misses currsize maxsize\n"
1124);
1125
1126static PyMethodDef lru_cache_methods[] = {
1127 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1128 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001129 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001130 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1131 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001132 {NULL}
1133};
1134
1135static PyGetSetDef lru_cache_getsetlist[] = {
1136 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1137 {NULL}
1138};
1139
1140static PyTypeObject lru_cache_type = {
1141 PyVarObject_HEAD_INIT(NULL, 0)
1142 "functools._lru_cache_wrapper", /* tp_name */
1143 sizeof(lru_cache_object), /* tp_basicsize */
1144 0, /* tp_itemsize */
1145 /* methods */
1146 (destructor)lru_cache_dealloc, /* tp_dealloc */
1147 0, /* tp_print */
1148 0, /* tp_getattr */
1149 0, /* tp_setattr */
1150 0, /* tp_reserved */
1151 0, /* tp_repr */
1152 0, /* tp_as_number */
1153 0, /* tp_as_sequence */
1154 0, /* tp_as_mapping */
1155 0, /* tp_hash */
1156 (ternaryfunc)lru_cache_call, /* tp_call */
1157 0, /* tp_str */
1158 0, /* tp_getattro */
1159 0, /* tp_setattro */
1160 0, /* tp_as_buffer */
1161 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1162 /* tp_flags */
1163 lru_cache_doc, /* tp_doc */
1164 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1165 (inquiry)lru_cache_tp_clear, /* tp_clear */
1166 0, /* tp_richcompare */
1167 0, /* tp_weaklistoffset */
1168 0, /* tp_iter */
1169 0, /* tp_iternext */
1170 lru_cache_methods, /* tp_methods */
1171 0, /* tp_members */
1172 lru_cache_getsetlist, /* tp_getset */
1173 0, /* tp_base */
1174 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001175 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001176 0, /* tp_descr_set */
1177 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1178 0, /* tp_init */
1179 0, /* tp_alloc */
1180 lru_cache_new, /* tp_new */
1181};
1182
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001183/* module level code ********************************************************/
1184
1185PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001186"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001187
1188static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001189 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001190 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1191 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001192 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001193};
1194
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001195static void
1196module_free(void *m)
1197{
1198 Py_CLEAR(kwd_mark);
1199}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001200
1201static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001202 PyModuleDef_HEAD_INIT,
1203 "_functools",
1204 module_doc,
1205 -1,
1206 module_methods,
1207 NULL,
1208 NULL,
1209 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001210 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001211};
1212
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001213PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001214PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001215{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001216 int i;
1217 PyObject *m;
1218 char *name;
1219 PyTypeObject *typelist[] = {
1220 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001221 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001222 NULL
1223 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001224
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001225 m = PyModule_Create(&_functoolsmodule);
1226 if (m == NULL)
1227 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001228
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001229 kwd_mark = PyObject_CallObject((PyObject *)&PyBaseObject_Type, NULL);
1230 if (!kwd_mark) {
1231 Py_DECREF(m);
1232 return NULL;
1233 }
1234
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001235 for (i=0 ; typelist[i] != NULL ; i++) {
1236 if (PyType_Ready(typelist[i]) < 0) {
1237 Py_DECREF(m);
1238 return NULL;
1239 }
1240 name = strchr(typelist[i]->tp_name, '.');
1241 assert (name != NULL);
1242 Py_INCREF(typelist[i]);
1243 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1244 }
1245 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001246}