blob: fa5fad3e754e79d5a2ad981b00c4fcbfd7a15e14 [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{
707 PyObject *key, *sorted_items;
708 Py_ssize_t key_size, pos, key_pos;
709
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
716 if (kwds && PyDict_Size(kwds) > 0) {
717 sorted_items = PyDict_Items(kwds);
718 if (!sorted_items)
719 return NULL;
720 if (PyList_Sort(sorted_items) < 0) {
721 Py_DECREF(sorted_items);
722 return NULL;
723 }
724 } else
725 sorted_items = NULL;
726
727 key_size = PyTuple_GET_SIZE(args);
728 if (sorted_items)
729 key_size += PyList_GET_SIZE(sorted_items);
730 if (typed)
731 key_size *= 2;
732 if (sorted_items)
733 key_size++;
734
735 key = PyTuple_New(key_size);
736 if (key == NULL)
737 goto done;
738
739 key_pos = 0;
740 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
741 PyObject *item = PyTuple_GET_ITEM(args, pos);
742 Py_INCREF(item);
743 PyTuple_SET_ITEM(key, key_pos++, item);
744 }
745 if (sorted_items) {
746 Py_INCREF(kwd_mark);
747 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
748 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
749 PyObject *item = PyList_GET_ITEM(sorted_items, pos);
750 Py_INCREF(item);
751 PyTuple_SET_ITEM(key, key_pos++, item);
752 }
753 }
754 if (typed) {
755 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
756 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
757 Py_INCREF(item);
758 PyTuple_SET_ITEM(key, key_pos++, item);
759 }
760 if (sorted_items) {
761 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
762 PyObject *tp_items = PyList_GET_ITEM(sorted_items, pos);
763 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(tp_items, 1));
764 Py_INCREF(item);
765 PyTuple_SET_ITEM(key, key_pos++, item);
766 }
767 }
768 }
769 assert(key_pos == key_size);
770
771done:
772 if (sorted_items)
773 Py_DECREF(sorted_items);
774 return key;
775}
776
777static PyObject *
778uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
779{
780 PyObject *result = PyObject_Call(self->func, args, kwds);
781 if (!result)
782 return NULL;
783 self->misses++;
784 return result;
785}
786
787static PyObject *
788infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
789{
790 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300791 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300792 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
793 if (!key)
794 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300795 hash = PyObject_Hash(key);
796 if (hash == -1)
797 return NULL;
798 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300799 if (result) {
800 Py_INCREF(result);
801 self->hits++;
802 Py_DECREF(key);
803 return result;
804 }
805 if (PyErr_Occurred()) {
806 Py_DECREF(key);
807 return NULL;
808 }
809 result = PyObject_Call(self->func, args, kwds);
810 if (!result) {
811 Py_DECREF(key);
812 return NULL;
813 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300814 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300815 Py_DECREF(result);
816 Py_DECREF(key);
817 return NULL;
818 }
819 Py_DECREF(key);
820 self->misses++;
821 return result;
822}
823
824static void
825lru_cache_extricate_link(lru_list_elem *link)
826{
827 link->prev->next = link->next;
828 link->next->prev = link->prev;
829}
830
831static void
832lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
833{
834 lru_list_elem *root = &self->root;
835 lru_list_elem *last = root->prev;
836 last->next = root->prev = link;
837 link->prev = last;
838 link->next = root;
839}
840
841static PyObject *
842bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
843{
844 lru_list_elem *link;
845 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300846 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300847
848 key = lru_cache_make_key(args, kwds, self->typed);
849 if (!key)
850 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300851 hash = PyObject_Hash(key);
852 if (hash == -1)
853 return NULL;
854 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300855 if (link) {
856 lru_cache_extricate_link(link);
857 lru_cache_append_link(self, link);
858 self->hits++;
859 result = link->result;
860 Py_INCREF(result);
861 Py_DECREF(key);
862 return result;
863 }
864 if (PyErr_Occurred()) {
865 Py_DECREF(key);
866 return NULL;
867 }
868 result = PyObject_Call(self->func, args, kwds);
869 if (!result) {
870 Py_DECREF(key);
871 return NULL;
872 }
873 if (self->full && self->root.next != &self->root) {
874 /* Use the oldest item to store the new key and result. */
875 PyObject *oldkey, *oldresult;
876 /* Extricate the oldest item. */
877 link = self->root.next;
878 lru_cache_extricate_link(link);
879 /* Remove it from the cache.
880 The cache dict holds one reference to the link,
881 and the linked list holds yet one reference to it. */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300882 if (_PyDict_DelItem_KnownHash(self->cache, link->key,
883 link->hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300884 lru_cache_append_link(self, link);
885 Py_DECREF(key);
886 Py_DECREF(result);
887 return NULL;
888 }
889 /* Keep a reference to the old key and old result to
890 prevent their ref counts from going to zero during the
891 update. That will prevent potentially arbitrary object
892 clean-up code (i.e. __del__) from running while we're
893 still adjusting the links. */
894 oldkey = link->key;
895 oldresult = link->result;
896
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300897 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300898 link->key = key;
899 link->result = result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300900 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
901 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300902 Py_DECREF(link);
903 Py_DECREF(oldkey);
904 Py_DECREF(oldresult);
905 return NULL;
906 }
907 lru_cache_append_link(self, link);
908 Py_INCREF(result); /* for return */
909 Py_DECREF(oldkey);
910 Py_DECREF(oldresult);
911 } else {
912 /* Put result in a new link at the front of the queue. */
913 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
914 &lru_list_elem_type);
915 if (link == NULL) {
916 Py_DECREF(key);
917 Py_DECREF(result);
918 return NULL;
919 }
920
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300921 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300922 link->key = key;
923 link->result = result;
924 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300925 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
926 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300927 Py_DECREF(link);
928 return NULL;
929 }
930 lru_cache_append_link(self, link);
931 Py_INCREF(result); /* for return */
932 self->full = (PyDict_Size(self->cache) >= self->maxsize);
933 }
934 self->misses++;
935 return result;
936}
937
938static PyObject *
939lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
940{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300941 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300942 int typed;
943 lru_cache_object *obj;
944 Py_ssize_t maxsize;
945 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
946 static char *keywords[] = {"user_function", "maxsize", "typed",
947 "cache_info_type", NULL};
948
949 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
950 &func, &maxsize_O, &typed,
951 &cache_info_type)) {
952 return NULL;
953 }
954
955 if (!PyCallable_Check(func)) {
956 PyErr_SetString(PyExc_TypeError,
957 "the first argument must be callable");
958 return NULL;
959 }
960
961 /* select the caching function, and make/inc maxsize_O */
962 if (maxsize_O == Py_None) {
963 wrapper = infinite_lru_cache_wrapper;
964 /* use this only to initialize lru_cache_object attribute maxsize */
965 maxsize = -1;
966 } else if (PyIndex_Check(maxsize_O)) {
967 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
968 if (maxsize == -1 && PyErr_Occurred())
969 return NULL;
970 if (maxsize == 0)
971 wrapper = uncached_lru_cache_wrapper;
972 else
973 wrapper = bounded_lru_cache_wrapper;
974 } else {
975 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
976 return NULL;
977 }
978
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300979 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300980 return NULL;
981
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300982 obj = (lru_cache_object *)type->tp_alloc(type, 0);
983 if (obj == NULL) {
984 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300985 return NULL;
986 }
987
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300988 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300989 obj->root.prev = &obj->root;
990 obj->root.next = &obj->root;
991 obj->maxsize = maxsize;
992 Py_INCREF(maxsize_O);
993 obj->maxsize_O = maxsize_O;
994 Py_INCREF(func);
995 obj->func = func;
996 obj->wrapper = wrapper;
997 obj->misses = obj->hits = 0;
998 obj->typed = typed;
999 Py_INCREF(cache_info_type);
1000 obj->cache_info_type = cache_info_type;
1001
1002 return (PyObject *)obj;
1003}
1004
1005static lru_list_elem *
1006lru_cache_unlink_list(lru_cache_object *self)
1007{
1008 lru_list_elem *root = &self->root;
1009 lru_list_elem *link = root->next;
1010 if (link == root)
1011 return NULL;
1012 root->prev->next = NULL;
1013 root->next = root->prev = root;
1014 return link;
1015}
1016
1017static void
1018lru_cache_clear_list(lru_list_elem *link)
1019{
1020 while (link != NULL) {
1021 lru_list_elem *next = link->next;
1022 Py_DECREF(link);
1023 link = next;
1024 }
1025}
1026
1027static void
1028lru_cache_dealloc(lru_cache_object *obj)
1029{
1030 lru_list_elem *list = lru_cache_unlink_list(obj);
1031 Py_XDECREF(obj->maxsize_O);
1032 Py_XDECREF(obj->func);
1033 Py_XDECREF(obj->cache);
1034 Py_XDECREF(obj->dict);
1035 Py_XDECREF(obj->cache_info_type);
1036 lru_cache_clear_list(list);
1037 Py_TYPE(obj)->tp_free(obj);
1038}
1039
1040static PyObject *
1041lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1042{
1043 return self->wrapper(self, args, kwds);
1044}
1045
1046static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001047lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1048{
1049 if (obj == Py_None || obj == NULL) {
1050 Py_INCREF(self);
1051 return self;
1052 }
1053 return PyMethod_New(self, obj);
1054}
1055
1056static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001057lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1058{
1059 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1060 self->hits, self->misses, self->maxsize_O,
1061 PyDict_Size(self->cache));
1062}
1063
1064static PyObject *
1065lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1066{
1067 lru_list_elem *list = lru_cache_unlink_list(self);
1068 self->hits = self->misses = 0;
1069 self->full = 0;
1070 PyDict_Clear(self->cache);
1071 lru_cache_clear_list(list);
1072 Py_RETURN_NONE;
1073}
1074
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001075static PyObject *
1076lru_cache_reduce(PyObject *self, PyObject *unused)
1077{
1078 return PyObject_GetAttrString(self, "__qualname__");
1079}
1080
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001081static PyObject *
1082lru_cache_copy(PyObject *self, PyObject *unused)
1083{
1084 Py_INCREF(self);
1085 return self;
1086}
1087
1088static PyObject *
1089lru_cache_deepcopy(PyObject *self, PyObject *unused)
1090{
1091 Py_INCREF(self);
1092 return self;
1093}
1094
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001095static int
1096lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1097{
1098 lru_list_elem *link = self->root.next;
1099 while (link != &self->root) {
1100 lru_list_elem *next = link->next;
1101 Py_VISIT(link);
1102 link = next;
1103 }
1104 Py_VISIT(self->maxsize_O);
1105 Py_VISIT(self->func);
1106 Py_VISIT(self->cache);
1107 Py_VISIT(self->cache_info_type);
1108 Py_VISIT(self->dict);
1109 return 0;
1110}
1111
1112static int
1113lru_cache_tp_clear(lru_cache_object *self)
1114{
1115 lru_list_elem *list = lru_cache_unlink_list(self);
1116 Py_CLEAR(self->maxsize_O);
1117 Py_CLEAR(self->func);
1118 Py_CLEAR(self->cache);
1119 Py_CLEAR(self->cache_info_type);
1120 Py_CLEAR(self->dict);
1121 lru_cache_clear_list(list);
1122 return 0;
1123}
1124
1125
1126PyDoc_STRVAR(lru_cache_doc,
1127"Create a cached callable that wraps another function.\n\
1128\n\
1129user_function: the function being cached\n\
1130\n\
1131maxsize: 0 for no caching\n\
1132 None for unlimited cache size\n\
1133 n for a bounded cache\n\
1134\n\
1135typed: False cache f(3) and f(3.0) as identical calls\n\
1136 True cache f(3) and f(3.0) as distinct calls\n\
1137\n\
1138cache_info_type: namedtuple class with the fields:\n\
1139 hits misses currsize maxsize\n"
1140);
1141
1142static PyMethodDef lru_cache_methods[] = {
1143 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1144 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001145 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001146 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1147 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001148 {NULL}
1149};
1150
1151static PyGetSetDef lru_cache_getsetlist[] = {
1152 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1153 {NULL}
1154};
1155
1156static PyTypeObject lru_cache_type = {
1157 PyVarObject_HEAD_INIT(NULL, 0)
1158 "functools._lru_cache_wrapper", /* tp_name */
1159 sizeof(lru_cache_object), /* tp_basicsize */
1160 0, /* tp_itemsize */
1161 /* methods */
1162 (destructor)lru_cache_dealloc, /* tp_dealloc */
1163 0, /* tp_print */
1164 0, /* tp_getattr */
1165 0, /* tp_setattr */
1166 0, /* tp_reserved */
1167 0, /* tp_repr */
1168 0, /* tp_as_number */
1169 0, /* tp_as_sequence */
1170 0, /* tp_as_mapping */
1171 0, /* tp_hash */
1172 (ternaryfunc)lru_cache_call, /* tp_call */
1173 0, /* tp_str */
1174 0, /* tp_getattro */
1175 0, /* tp_setattro */
1176 0, /* tp_as_buffer */
1177 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1178 /* tp_flags */
1179 lru_cache_doc, /* tp_doc */
1180 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1181 (inquiry)lru_cache_tp_clear, /* tp_clear */
1182 0, /* tp_richcompare */
1183 0, /* tp_weaklistoffset */
1184 0, /* tp_iter */
1185 0, /* tp_iternext */
1186 lru_cache_methods, /* tp_methods */
1187 0, /* tp_members */
1188 lru_cache_getsetlist, /* tp_getset */
1189 0, /* tp_base */
1190 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001191 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001192 0, /* tp_descr_set */
1193 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1194 0, /* tp_init */
1195 0, /* tp_alloc */
1196 lru_cache_new, /* tp_new */
1197};
1198
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001199/* module level code ********************************************************/
1200
1201PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001202"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001203
1204static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001205 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001206 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1207 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001208 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001209};
1210
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001211static void
1212module_free(void *m)
1213{
1214 Py_CLEAR(kwd_mark);
1215}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001216
1217static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001218 PyModuleDef_HEAD_INIT,
1219 "_functools",
1220 module_doc,
1221 -1,
1222 module_methods,
1223 NULL,
1224 NULL,
1225 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001226 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001227};
1228
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001229PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001230PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001231{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001232 int i;
1233 PyObject *m;
1234 char *name;
1235 PyTypeObject *typelist[] = {
1236 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001237 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001238 NULL
1239 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001240
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001241 m = PyModule_Create(&_functoolsmodule);
1242 if (m == NULL)
1243 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001244
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001245 kwd_mark = PyObject_CallObject((PyObject *)&PyBaseObject_Type, NULL);
1246 if (!kwd_mark) {
1247 Py_DECREF(m);
1248 return NULL;
1249 }
1250
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001251 for (i=0 ; typelist[i] != NULL ; i++) {
1252 if (PyType_Ready(typelist[i]) < 0) {
1253 Py_DECREF(m);
1254 return NULL;
1255 }
1256 name = strchr(typelist[i]->tp_name, '.');
1257 assert (name != NULL);
1258 Py_INCREF(typelist[i]);
1259 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1260 }
1261 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001262}