blob: 7abc9f464027f7712dc4a021bcf51e5d55c5fdc3 [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 }
Serhiy Storchakae48fd932017-02-21 18:18:27 +020091 else if (Py_REFCNT(kw) == 1) {
Serhiy Storchaka38741282016-02-02 18:45:17 +020092 Py_INCREF(kw);
93 pto->kw = kw;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000094 }
Serhiy Storchakae48fd932017-02-21 18:18:27 +020095 else {
96 pto->kw = PyDict_Copy(kw);
97 }
Alexander Belopolskye49af342015-03-01 15:08:17 -050098 }
99 else {
Serhiy Storchaka38741282016-02-02 18:45:17 +0200100 pto->kw = PyDict_Copy(pkw);
101 if (kw != NULL && pto->kw != NULL) {
102 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
Benjamin Petersondae2ef12015-05-09 00:29:08 -0400103 Py_DECREF(pto);
104 return NULL;
105 }
106 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000107 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200108 if (pto->kw == NULL) {
109 Py_DECREF(pto);
110 return NULL;
111 }
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000112
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 return (PyObject *)pto;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000114}
115
116static void
117partial_dealloc(partialobject *pto)
118{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000119 PyObject_GC_UnTrack(pto);
120 if (pto->weakreflist != NULL)
121 PyObject_ClearWeakRefs((PyObject *) pto);
122 Py_XDECREF(pto->fn);
123 Py_XDECREF(pto->args);
124 Py_XDECREF(pto->kw);
125 Py_XDECREF(pto->dict);
126 Py_TYPE(pto)->tp_free(pto);
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000127}
128
129static PyObject *
130partial_call(partialobject *pto, PyObject *args, PyObject *kw)
131{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 PyObject *ret;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200133 PyObject *argappl, *kwappl;
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200134 PyObject **stack;
135 Py_ssize_t nargs;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000136
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 assert (PyCallable_Check(pto->fn));
138 assert (PyTuple_Check(pto->args));
Serhiy Storchaka38741282016-02-02 18:45:17 +0200139 assert (PyDict_Check(pto->kw));
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000140
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000141 if (PyTuple_GET_SIZE(pto->args) == 0) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200142 stack = &PyTuple_GET_ITEM(args, 0);
143 nargs = PyTuple_GET_SIZE(args);
144 argappl = NULL;
145 }
146 else if (PyTuple_GET_SIZE(args) == 0) {
147 stack = &PyTuple_GET_ITEM(pto->args, 0);
148 nargs = PyTuple_GET_SIZE(pto->args);
149 argappl = NULL;
150 }
151 else {
152 stack = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000153 argappl = PySequence_Concat(pto->args, args);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200154 if (argappl == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000155 return NULL;
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200156 }
157
Serhiy Storchaka38741282016-02-02 18:45:17 +0200158 assert(PyTuple_Check(argappl));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000160
Serhiy Storchaka38741282016-02-02 18:45:17 +0200161 if (PyDict_Size(pto->kw) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 kwappl = kw;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200163 Py_XINCREF(kwappl);
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200164 }
165 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 kwappl = PyDict_Copy(pto->kw);
167 if (kwappl == NULL) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200168 Py_XDECREF(argappl);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000169 return NULL;
170 }
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 if (kw != NULL) {
173 if (PyDict_Merge(kwappl, kw, 1) != 0) {
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200174 Py_XDECREF(argappl);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 Py_DECREF(kwappl);
176 return NULL;
177 }
178 }
179 }
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000180
Victor Stinnerf4d28d42016-08-23 16:22:35 +0200181 if (stack) {
182 ret = _PyObject_FastCallDict(pto->fn, stack, nargs, kwappl);
183 }
184 else {
185 ret = PyObject_Call(pto->fn, argappl, kwappl);
186 Py_DECREF(argappl);
187 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000188 Py_XDECREF(kwappl);
189 return ret;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000190}
191
192static int
193partial_traverse(partialobject *pto, visitproc visit, void *arg)
194{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 Py_VISIT(pto->fn);
196 Py_VISIT(pto->args);
197 Py_VISIT(pto->kw);
198 Py_VISIT(pto->dict);
199 return 0;
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000200}
201
202PyDoc_STRVAR(partial_doc,
203"partial(func, *args, **keywords) - new function with partial application\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 of the given arguments and keywords.\n");
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000205
206#define OFF(x) offsetof(partialobject, x)
207static PyMemberDef partial_memberlist[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 {"func", T_OBJECT, OFF(fn), READONLY,
209 "function object to use in future partial calls"},
210 {"args", T_OBJECT, OFF(args), READONLY,
211 "tuple of arguments to future partial calls"},
212 {"keywords", T_OBJECT, OFF(kw), READONLY,
213 "dictionary of keyword arguments to future partial calls"},
214 {NULL} /* Sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000215};
216
Georg Brandlc2fb6c72006-02-21 17:49:57 +0000217static PyGetSetDef partial_getsetlist[] = {
Benjamin Peterson23d7f122012-02-19 20:02:57 -0500218 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000219 {NULL} /* Sentinel */
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000220};
221
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000222static PyObject *
223partial_repr(partialobject *pto)
224{
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300225 PyObject *result = NULL;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000226 PyObject *arglist;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000227 Py_ssize_t i, n;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200228 PyObject *key, *value;
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300229 int status;
230
231 status = Py_ReprEnter((PyObject *)pto);
232 if (status != 0) {
233 if (status < 0)
234 return NULL;
Nick Coghlan457fc9a2016-09-10 20:00:02 +1000235 return PyUnicode_FromString("...");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300236 }
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000237
238 arglist = PyUnicode_FromString("");
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300239 if (arglist == NULL)
240 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000241 /* Pack positional arguments */
242 assert (PyTuple_Check(pto->args));
243 n = PyTuple_GET_SIZE(pto->args);
244 for (i = 0; i < n; i++) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300245 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
246 PyTuple_GET_ITEM(pto->args, i)));
247 if (arglist == NULL)
248 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000249 }
250 /* Pack keyword arguments */
Serhiy Storchaka38741282016-02-02 18:45:17 +0200251 assert (PyDict_Check(pto->kw));
252 for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300253 Py_SETREF(arglist, PyUnicode_FromFormat("%U, %U=%R", arglist,
254 key, value));
255 if (arglist == NULL)
256 goto done;
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000257 }
258 result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
259 pto->fn, arglist);
260 Py_DECREF(arglist);
Serhiy Storchaka179f9602016-06-12 11:44:06 +0300261
262 done:
263 Py_ReprLeave((PyObject *)pto);
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000264 return result;
265}
266
Jack Diederiche0cbd692009-04-01 04:27:09 +0000267/* Pickle strategy:
268 __reduce__ by itself doesn't support getting kwargs in the unpickle
269 operation so we define a __setstate__ that replaces all the information
270 about the partial. If we only replaced part of it someone would use
Ezio Melotti13925002011-03-16 11:05:33 +0200271 it as a hook to do strange things.
Jack Diederiche0cbd692009-04-01 04:27:09 +0000272 */
273
Antoine Pitrou69f71142009-05-24 21:25:49 +0000274static PyObject *
Jack Diederiche0cbd692009-04-01 04:27:09 +0000275partial_reduce(partialobject *pto, PyObject *unused)
276{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
278 pto->args, pto->kw,
279 pto->dict ? pto->dict : Py_None);
Jack Diederiche0cbd692009-04-01 04:27:09 +0000280}
281
Antoine Pitrou69f71142009-05-24 21:25:49 +0000282static PyObject *
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200283partial_setstate(partialobject *pto, PyObject *state)
Jack Diederiche0cbd692009-04-01 04:27:09 +0000284{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000285 PyObject *fn, *fnargs, *kw, *dict;
Serhiy Storchaka38741282016-02-02 18:45:17 +0200286
287 if (!PyTuple_Check(state) ||
288 !PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) ||
289 !PyCallable_Check(fn) ||
290 !PyTuple_Check(fnargs) ||
291 (kw != Py_None && !PyDict_Check(kw)))
292 {
293 PyErr_SetString(PyExc_TypeError, "invalid partial state");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000294 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 }
Serhiy Storchaka38741282016-02-02 18:45:17 +0200296
297 if(!PyTuple_CheckExact(fnargs))
298 fnargs = PySequence_Tuple(fnargs);
299 else
300 Py_INCREF(fnargs);
301 if (fnargs == NULL)
302 return NULL;
303
304 if (kw == Py_None)
305 kw = PyDict_New();
306 else if(!PyDict_CheckExact(kw))
307 kw = PyDict_Copy(kw);
308 else
309 Py_INCREF(kw);
310 if (kw == NULL) {
311 Py_DECREF(fnargs);
312 return NULL;
313 }
314
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000315 Py_INCREF(fn);
Serhiy Storchaka38741282016-02-02 18:45:17 +0200316 if (dict == Py_None)
317 dict = NULL;
318 else
319 Py_INCREF(dict);
320
Serhiy Storchaka864b63c2016-04-11 09:53:37 +0300321 Py_SETREF(pto->fn, fn);
322 Py_SETREF(pto->args, fnargs);
323 Py_SETREF(pto->kw, kw);
Serhiy Storchaka48842712016-04-06 09:45:48 +0300324 Py_XSETREF(pto->dict, dict);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 Py_RETURN_NONE;
Jack Diederiche0cbd692009-04-01 04:27:09 +0000326}
327
328static PyMethodDef partial_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 {"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
Serhiy Storchaka19c4e0d2013-02-04 12:47:24 +0200330 {"__setstate__", (PyCFunction)partial_setstate, METH_O},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 {NULL, NULL} /* sentinel */
Jack Diederiche0cbd692009-04-01 04:27:09 +0000332};
333
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000334static PyTypeObject partial_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000335 PyVarObject_HEAD_INIT(NULL, 0)
336 "functools.partial", /* tp_name */
337 sizeof(partialobject), /* tp_basicsize */
338 0, /* tp_itemsize */
339 /* methods */
340 (destructor)partial_dealloc, /* tp_dealloc */
341 0, /* tp_print */
342 0, /* tp_getattr */
343 0, /* tp_setattr */
344 0, /* tp_reserved */
Alexander Belopolsky41e422a2010-12-01 20:05:49 +0000345 (reprfunc)partial_repr, /* tp_repr */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000346 0, /* tp_as_number */
347 0, /* tp_as_sequence */
348 0, /* tp_as_mapping */
349 0, /* tp_hash */
350 (ternaryfunc)partial_call, /* tp_call */
351 0, /* tp_str */
352 PyObject_GenericGetAttr, /* tp_getattro */
353 PyObject_GenericSetAttr, /* tp_setattro */
354 0, /* tp_as_buffer */
355 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
356 Py_TPFLAGS_BASETYPE, /* tp_flags */
357 partial_doc, /* tp_doc */
358 (traverseproc)partial_traverse, /* tp_traverse */
359 0, /* tp_clear */
360 0, /* tp_richcompare */
361 offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
362 0, /* tp_iter */
363 0, /* tp_iternext */
364 partial_methods, /* tp_methods */
365 partial_memberlist, /* tp_members */
366 partial_getsetlist, /* tp_getset */
367 0, /* tp_base */
368 0, /* tp_dict */
369 0, /* tp_descr_get */
370 0, /* tp_descr_set */
371 offsetof(partialobject, dict), /* tp_dictoffset */
372 0, /* tp_init */
373 0, /* tp_alloc */
374 partial_new, /* tp_new */
375 PyObject_GC_Del, /* tp_free */
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000376};
377
378
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700379/* cmp_to_key ***************************************************************/
380
381typedef struct {
Victor Stinner446c8d52011-04-05 12:21:35 +0200382 PyObject_HEAD
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700383 PyObject *cmp;
384 PyObject *object;
385} keyobject;
386
387static void
388keyobject_dealloc(keyobject *ko)
389{
390 Py_DECREF(ko->cmp);
391 Py_XDECREF(ko->object);
392 PyObject_FREE(ko);
393}
394
395static int
396keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
397{
398 Py_VISIT(ko->cmp);
399 if (ko->object)
400 Py_VISIT(ko->object);
401 return 0;
402}
403
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500404static int
405keyobject_clear(keyobject *ko)
406{
407 Py_CLEAR(ko->cmp);
408 if (ko->object)
409 Py_CLEAR(ko->object);
410 return 0;
411}
412
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700413static PyMemberDef keyobject_members[] = {
414 {"obj", T_OBJECT,
415 offsetof(keyobject, object), 0,
416 PyDoc_STR("Value wrapped by a key function.")},
417 {NULL}
418};
419
420static PyObject *
Raymond Hettingera5632862011-04-09 12:57:00 -0700421keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700422
423static PyObject *
424keyobject_richcompare(PyObject *ko, PyObject *other, int op);
425
426static PyTypeObject keyobject_type = {
427 PyVarObject_HEAD_INIT(&PyType_Type, 0)
428 "functools.KeyWrapper", /* tp_name */
429 sizeof(keyobject), /* tp_basicsize */
430 0, /* tp_itemsize */
431 /* methods */
432 (destructor)keyobject_dealloc, /* tp_dealloc */
433 0, /* tp_print */
434 0, /* tp_getattr */
435 0, /* tp_setattr */
436 0, /* tp_reserved */
437 0, /* tp_repr */
438 0, /* tp_as_number */
439 0, /* tp_as_sequence */
440 0, /* tp_as_mapping */
441 0, /* tp_hash */
442 (ternaryfunc)keyobject_call, /* tp_call */
443 0, /* tp_str */
444 PyObject_GenericGetAttr, /* tp_getattro */
445 0, /* tp_setattro */
446 0, /* tp_as_buffer */
447 Py_TPFLAGS_DEFAULT, /* tp_flags */
448 0, /* tp_doc */
449 (traverseproc)keyobject_traverse, /* tp_traverse */
Benjamin Peterson3bd97292011-04-05 17:25:14 -0500450 (inquiry)keyobject_clear, /* tp_clear */
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700451 keyobject_richcompare, /* tp_richcompare */
452 0, /* tp_weaklistoffset */
453 0, /* tp_iter */
454 0, /* tp_iternext */
455 0, /* tp_methods */
456 keyobject_members, /* tp_members */
457 0, /* tp_getset */
458};
459
460static PyObject *
461keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
462{
463 PyObject *object;
464 keyobject *result;
465 static char *kwargs[] = {"obj", NULL};
466
467 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
468 return NULL;
469 result = PyObject_New(keyobject, &keyobject_type);
470 if (!result)
471 return NULL;
472 Py_INCREF(ko->cmp);
473 result->cmp = ko->cmp;
474 Py_INCREF(object);
475 result->object = object;
476 return (PyObject *)result;
477}
478
479static PyObject *
480keyobject_richcompare(PyObject *ko, PyObject *other, int op)
481{
482 PyObject *res;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700483 PyObject *x;
484 PyObject *y;
485 PyObject *compare;
486 PyObject *answer;
487 static PyObject *zero;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200488 PyObject* stack[2];
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700489
490 if (zero == NULL) {
491 zero = PyLong_FromLong(0);
492 if (!zero)
493 return NULL;
494 }
495
496 if (Py_TYPE(other) != &keyobject_type){
497 PyErr_Format(PyExc_TypeError, "other argument must be K instance");
498 return NULL;
499 }
500 compare = ((keyobject *) ko)->cmp;
501 assert(compare != NULL);
502 x = ((keyobject *) ko)->object;
503 y = ((keyobject *) other)->object;
504 if (!x || !y){
505 PyErr_Format(PyExc_AttributeError, "object");
506 return NULL;
507 }
508
509 /* Call the user's comparison function and translate the 3-way
510 * result into true or false (or error).
511 */
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200512 stack[0] = x;
513 stack[1] = y;
Victor Stinner559bb6a2016-08-22 22:48:54 +0200514 res = _PyObject_FastCall(compare, stack, 2);
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200515 if (res == NULL) {
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700516 return NULL;
Victor Stinnerf7a4c482016-08-19 18:52:35 +0200517 }
518
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700519 answer = PyObject_RichCompare(res, zero, op);
520 Py_DECREF(res);
521 return answer;
522}
523
524static PyObject *
Victor Stinner446c8d52011-04-05 12:21:35 +0200525functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
526{
527 PyObject *cmp;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700528 static char *kwargs[] = {"mycmp", NULL};
Victor Stinner446c8d52011-04-05 12:21:35 +0200529 keyobject *object;
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700530
531 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
532 return NULL;
Victor Stinner446c8d52011-04-05 12:21:35 +0200533 object = PyObject_New(keyobject, &keyobject_type);
Raymond Hettinger7ab9e222011-04-05 02:33:54 -0700534 if (!object)
535 return NULL;
536 Py_INCREF(cmp);
537 object->cmp = cmp;
538 object->object = NULL;
539 return (PyObject *)object;
540}
541
542PyDoc_STRVAR(functools_cmp_to_key_doc,
543"Convert a cmp= function into a key= function.");
544
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000545/* reduce (used to be a builtin) ********************************************/
546
547static PyObject *
548functools_reduce(PyObject *self, PyObject *args)
549{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000550 PyObject *seq, *func, *result = NULL, *it;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000551
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000552 if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
553 return NULL;
554 if (result != NULL)
555 Py_INCREF(result);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000556
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000557 it = PyObject_GetIter(seq);
558 if (it == NULL) {
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000559 if (PyErr_ExceptionMatches(PyExc_TypeError))
560 PyErr_SetString(PyExc_TypeError,
561 "reduce() arg 2 must support iteration");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000562 Py_XDECREF(result);
563 return NULL;
564 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000565
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000566 if ((args = PyTuple_New(2)) == NULL)
567 goto Fail;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000568
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000569 for (;;) {
570 PyObject *op2;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000571
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000572 if (args->ob_refcnt > 1) {
573 Py_DECREF(args);
574 if ((args = PyTuple_New(2)) == NULL)
575 goto Fail;
576 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000577
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000578 op2 = PyIter_Next(it);
579 if (op2 == NULL) {
580 if (PyErr_Occurred())
581 goto Fail;
582 break;
583 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000584
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000585 if (result == NULL)
586 result = op2;
587 else {
588 PyTuple_SetItem(args, 0, result);
589 PyTuple_SetItem(args, 1, op2);
590 if ((result = PyEval_CallObject(func, args)) == NULL)
591 goto Fail;
592 }
593 }
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000594
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000595 Py_DECREF(args);
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000596
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000597 if (result == NULL)
598 PyErr_SetString(PyExc_TypeError,
599 "reduce() of empty sequence with no initial value");
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000600
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000601 Py_DECREF(it);
602 return result;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000603
604Fail:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000605 Py_XDECREF(args);
606 Py_XDECREF(result);
607 Py_DECREF(it);
608 return NULL;
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000609}
610
611PyDoc_STRVAR(functools_reduce_doc,
612"reduce(function, sequence[, initial]) -> value\n\
613\n\
614Apply a function of two arguments cumulatively to the items of a sequence,\n\
615from left to right, so as to reduce the sequence to a single value.\n\
616For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
617((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
618of the sequence in the calculation, and serves as a default when the\n\
619sequence is empty.");
620
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300621/* lru_cache object **********************************************************/
622
623/* this object is used delimit args and keywords in the cache keys */
624static PyObject *kwd_mark = NULL;
625
626struct lru_list_elem;
627struct lru_cache_object;
628
629typedef struct lru_list_elem {
630 PyObject_HEAD
631 struct lru_list_elem *prev, *next; /* borrowed links */
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300632 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300633 PyObject *key, *result;
634} lru_list_elem;
635
636static void
637lru_list_elem_dealloc(lru_list_elem *link)
638{
639 _PyObject_GC_UNTRACK(link);
640 Py_XDECREF(link->key);
641 Py_XDECREF(link->result);
642 PyObject_GC_Del(link);
643}
644
645static int
646lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
647{
648 Py_VISIT(link->key);
649 Py_VISIT(link->result);
650 return 0;
651}
652
653static int
654lru_list_elem_clear(lru_list_elem *link)
655{
656 Py_CLEAR(link->key);
657 Py_CLEAR(link->result);
658 return 0;
659}
660
661static PyTypeObject lru_list_elem_type = {
662 PyVarObject_HEAD_INIT(&PyType_Type, 0)
663 "functools._lru_list_elem", /* tp_name */
664 sizeof(lru_list_elem), /* tp_basicsize */
665 0, /* tp_itemsize */
666 /* methods */
667 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
668 0, /* tp_print */
669 0, /* tp_getattr */
670 0, /* tp_setattr */
671 0, /* tp_reserved */
672 0, /* tp_repr */
673 0, /* tp_as_number */
674 0, /* tp_as_sequence */
675 0, /* tp_as_mapping */
676 0, /* tp_hash */
677 0, /* tp_call */
678 0, /* tp_str */
679 0, /* tp_getattro */
680 0, /* tp_setattro */
681 0, /* tp_as_buffer */
682 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
683 0, /* tp_doc */
684 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
685 (inquiry)lru_list_elem_clear, /* tp_clear */
686};
687
688
689typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject *, PyObject *);
690
691typedef struct lru_cache_object {
692 lru_list_elem root; /* includes PyObject_HEAD */
693 Py_ssize_t maxsize;
694 PyObject *maxsize_O;
695 PyObject *func;
696 lru_cache_ternaryfunc wrapper;
697 PyObject *cache;
698 PyObject *cache_info_type;
699 Py_ssize_t misses, hits;
700 int typed;
701 PyObject *dict;
702 int full;
703} lru_cache_object;
704
705static PyTypeObject lru_cache_type;
706
707static PyObject *
708lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
709{
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800710 PyObject *key, *keyword, *value;
711 Py_ssize_t key_size, pos, key_pos, kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300712
713 /* short path, key will match args anyway, which is a tuple */
714 if (!typed && !kwds) {
715 Py_INCREF(args);
716 return args;
717 }
718
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800719 kwds_size = kwds ? PyDict_Size(kwds) : 0;
720 assert(kwds_size >= 0);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300721
722 key_size = PyTuple_GET_SIZE(args);
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800723 if (kwds_size)
724 key_size += kwds_size * 2 + 1;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300725 if (typed)
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800726 key_size += PyTuple_GET_SIZE(args) + kwds_size;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300727
728 key = PyTuple_New(key_size);
729 if (key == NULL)
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800730 return NULL;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300731
732 key_pos = 0;
733 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
734 PyObject *item = PyTuple_GET_ITEM(args, pos);
735 Py_INCREF(item);
736 PyTuple_SET_ITEM(key, key_pos++, item);
737 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800738 if (kwds_size) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300739 Py_INCREF(kwd_mark);
740 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800741 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
742 Py_INCREF(keyword);
743 PyTuple_SET_ITEM(key, key_pos++, keyword);
744 Py_INCREF(value);
745 PyTuple_SET_ITEM(key, key_pos++, value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300746 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800747 assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300748 }
749 if (typed) {
750 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
751 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
752 Py_INCREF(item);
753 PyTuple_SET_ITEM(key, key_pos++, item);
754 }
Raymond Hettinger4ee39142017-01-08 17:28:20 -0800755 if (kwds_size) {
756 for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
757 PyObject *item = (PyObject *)Py_TYPE(value);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300758 Py_INCREF(item);
759 PyTuple_SET_ITEM(key, key_pos++, item);
760 }
761 }
762 }
763 assert(key_pos == key_size);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300764 return key;
765}
766
767static PyObject *
768uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
769{
770 PyObject *result = PyObject_Call(self->func, args, kwds);
771 if (!result)
772 return NULL;
773 self->misses++;
774 return result;
775}
776
777static PyObject *
778infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
779{
780 PyObject *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300781 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300782 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
783 if (!key)
784 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300785 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500786 if (hash == -1) {
787 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300788 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500789 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300790 result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300791 if (result) {
792 Py_INCREF(result);
793 self->hits++;
794 Py_DECREF(key);
795 return result;
796 }
797 if (PyErr_Occurred()) {
798 Py_DECREF(key);
799 return NULL;
800 }
801 result = PyObject_Call(self->func, args, kwds);
802 if (!result) {
803 Py_DECREF(key);
804 return NULL;
805 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300806 if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300807 Py_DECREF(result);
808 Py_DECREF(key);
809 return NULL;
810 }
811 Py_DECREF(key);
812 self->misses++;
813 return result;
814}
815
816static void
817lru_cache_extricate_link(lru_list_elem *link)
818{
819 link->prev->next = link->next;
820 link->next->prev = link->prev;
821}
822
823static void
824lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
825{
826 lru_list_elem *root = &self->root;
827 lru_list_elem *last = root->prev;
828 last->next = root->prev = link;
829 link->prev = last;
830 link->next = root;
831}
832
833static PyObject *
834bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
835{
836 lru_list_elem *link;
837 PyObject *key, *result;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300838 Py_hash_t hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300839
840 key = lru_cache_make_key(args, kwds, self->typed);
841 if (!key)
842 return NULL;
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300843 hash = PyObject_Hash(key);
Yury Selivanov46a02db2016-11-09 18:55:45 -0500844 if (hash == -1) {
845 Py_DECREF(key);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300846 return NULL;
Yury Selivanov46a02db2016-11-09 18:55:45 -0500847 }
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300848 link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300849 if (link) {
850 lru_cache_extricate_link(link);
851 lru_cache_append_link(self, link);
852 self->hits++;
853 result = link->result;
854 Py_INCREF(result);
855 Py_DECREF(key);
856 return result;
857 }
858 if (PyErr_Occurred()) {
859 Py_DECREF(key);
860 return NULL;
861 }
862 result = PyObject_Call(self->func, args, kwds);
863 if (!result) {
864 Py_DECREF(key);
865 return NULL;
866 }
867 if (self->full && self->root.next != &self->root) {
868 /* Use the oldest item to store the new key and result. */
Serhiy Storchaka67796522017-01-12 18:34:33 +0200869 PyObject *oldkey, *oldresult, *popresult;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300870 /* Extricate the oldest item. */
871 link = self->root.next;
872 lru_cache_extricate_link(link);
873 /* Remove it from the cache.
874 The cache dict holds one reference to the link,
875 and the linked list holds yet one reference to it. */
Serhiy Storchaka42e1ea92017-01-12 19:12:21 +0200876 popresult = _PyDict_Pop_KnownHash(self->cache,
Serhiy Storchaka67796522017-01-12 18:34:33 +0200877 link->key, link->hash,
878 Py_None);
879 if (popresult == Py_None) {
880 /* Getting here means that this same key was added to the
881 cache while the lock was released. Since the link
882 update is already done, we need only return the
883 computed result and update the count of misses. */
884 Py_DECREF(popresult);
885 Py_DECREF(link);
886 Py_DECREF(key);
887 }
888 else if (popresult == NULL) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300889 lru_cache_append_link(self, link);
890 Py_DECREF(key);
891 Py_DECREF(result);
892 return NULL;
893 }
Serhiy Storchaka67796522017-01-12 18:34:33 +0200894 else {
895 Py_DECREF(popresult);
896 /* Keep a reference to the old key and old result to
897 prevent their ref counts from going to zero during the
898 update. That will prevent potentially arbitrary object
899 clean-up code (i.e. __del__) from running while we're
900 still adjusting the links. */
901 oldkey = link->key;
902 oldresult = link->result;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300903
Serhiy Storchaka67796522017-01-12 18:34:33 +0200904 link->hash = hash;
905 link->key = key;
906 link->result = result;
907 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
908 hash) < 0) {
909 Py_DECREF(link);
910 Py_DECREF(oldkey);
911 Py_DECREF(oldresult);
912 return NULL;
913 }
914 lru_cache_append_link(self, link);
915 Py_INCREF(result); /* for return */
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300916 Py_DECREF(oldkey);
917 Py_DECREF(oldresult);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300918 }
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300919 } else {
920 /* Put result in a new link at the front of the queue. */
921 link = (lru_list_elem *)PyObject_GC_New(lru_list_elem,
922 &lru_list_elem_type);
923 if (link == NULL) {
924 Py_DECREF(key);
925 Py_DECREF(result);
926 return NULL;
927 }
928
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300929 link->hash = hash;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300930 link->key = key;
931 link->result = result;
932 _PyObject_GC_TRACK(link);
Serhiy Storchakab9d98d52015-10-02 12:47:11 +0300933 if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
934 hash) < 0) {
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300935 Py_DECREF(link);
936 return NULL;
937 }
938 lru_cache_append_link(self, link);
939 Py_INCREF(result); /* for return */
940 self->full = (PyDict_Size(self->cache) >= self->maxsize);
941 }
942 self->misses++;
943 return result;
944}
945
946static PyObject *
947lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
948{
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300949 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300950 int typed;
951 lru_cache_object *obj;
952 Py_ssize_t maxsize;
953 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
954 static char *keywords[] = {"user_function", "maxsize", "typed",
955 "cache_info_type", NULL};
956
957 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
958 &func, &maxsize_O, &typed,
959 &cache_info_type)) {
960 return NULL;
961 }
962
963 if (!PyCallable_Check(func)) {
964 PyErr_SetString(PyExc_TypeError,
965 "the first argument must be callable");
966 return NULL;
967 }
968
969 /* select the caching function, and make/inc maxsize_O */
970 if (maxsize_O == Py_None) {
971 wrapper = infinite_lru_cache_wrapper;
972 /* use this only to initialize lru_cache_object attribute maxsize */
973 maxsize = -1;
974 } else if (PyIndex_Check(maxsize_O)) {
975 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
976 if (maxsize == -1 && PyErr_Occurred())
977 return NULL;
978 if (maxsize == 0)
979 wrapper = uncached_lru_cache_wrapper;
980 else
981 wrapper = bounded_lru_cache_wrapper;
982 } else {
983 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
984 return NULL;
985 }
986
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300987 if (!(cachedict = PyDict_New()))
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300988 return NULL;
989
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300990 obj = (lru_cache_object *)type->tp_alloc(type, 0);
991 if (obj == NULL) {
992 Py_DECREF(cachedict);
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300993 return NULL;
994 }
995
Serhiy Storchaka374164c2015-07-25 12:10:21 +0300996 obj->cache = cachedict;
Serhiy Storchaka46c56112015-05-24 21:53:49 +0300997 obj->root.prev = &obj->root;
998 obj->root.next = &obj->root;
999 obj->maxsize = maxsize;
1000 Py_INCREF(maxsize_O);
1001 obj->maxsize_O = maxsize_O;
1002 Py_INCREF(func);
1003 obj->func = func;
1004 obj->wrapper = wrapper;
1005 obj->misses = obj->hits = 0;
1006 obj->typed = typed;
1007 Py_INCREF(cache_info_type);
1008 obj->cache_info_type = cache_info_type;
1009
1010 return (PyObject *)obj;
1011}
1012
1013static lru_list_elem *
1014lru_cache_unlink_list(lru_cache_object *self)
1015{
1016 lru_list_elem *root = &self->root;
1017 lru_list_elem *link = root->next;
1018 if (link == root)
1019 return NULL;
1020 root->prev->next = NULL;
1021 root->next = root->prev = root;
1022 return link;
1023}
1024
1025static void
1026lru_cache_clear_list(lru_list_elem *link)
1027{
1028 while (link != NULL) {
1029 lru_list_elem *next = link->next;
1030 Py_DECREF(link);
1031 link = next;
1032 }
1033}
1034
1035static void
1036lru_cache_dealloc(lru_cache_object *obj)
1037{
1038 lru_list_elem *list = lru_cache_unlink_list(obj);
1039 Py_XDECREF(obj->maxsize_O);
1040 Py_XDECREF(obj->func);
1041 Py_XDECREF(obj->cache);
1042 Py_XDECREF(obj->dict);
1043 Py_XDECREF(obj->cache_info_type);
1044 lru_cache_clear_list(list);
1045 Py_TYPE(obj)->tp_free(obj);
1046}
1047
1048static PyObject *
1049lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1050{
1051 return self->wrapper(self, args, kwds);
1052}
1053
1054static PyObject *
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001055lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1056{
1057 if (obj == Py_None || obj == NULL) {
1058 Py_INCREF(self);
1059 return self;
1060 }
1061 return PyMethod_New(self, obj);
1062}
1063
1064static PyObject *
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001065lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1066{
1067 return PyObject_CallFunction(self->cache_info_type, "nnOn",
1068 self->hits, self->misses, self->maxsize_O,
1069 PyDict_Size(self->cache));
1070}
1071
1072static PyObject *
1073lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1074{
1075 lru_list_elem *list = lru_cache_unlink_list(self);
1076 self->hits = self->misses = 0;
1077 self->full = 0;
1078 PyDict_Clear(self->cache);
1079 lru_cache_clear_list(list);
1080 Py_RETURN_NONE;
1081}
1082
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001083static PyObject *
1084lru_cache_reduce(PyObject *self, PyObject *unused)
1085{
1086 return PyObject_GetAttrString(self, "__qualname__");
1087}
1088
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001089static PyObject *
1090lru_cache_copy(PyObject *self, PyObject *unused)
1091{
1092 Py_INCREF(self);
1093 return self;
1094}
1095
1096static PyObject *
1097lru_cache_deepcopy(PyObject *self, PyObject *unused)
1098{
1099 Py_INCREF(self);
1100 return self;
1101}
1102
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001103static int
1104lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1105{
1106 lru_list_elem *link = self->root.next;
1107 while (link != &self->root) {
1108 lru_list_elem *next = link->next;
1109 Py_VISIT(link);
1110 link = next;
1111 }
1112 Py_VISIT(self->maxsize_O);
1113 Py_VISIT(self->func);
1114 Py_VISIT(self->cache);
1115 Py_VISIT(self->cache_info_type);
1116 Py_VISIT(self->dict);
1117 return 0;
1118}
1119
1120static int
1121lru_cache_tp_clear(lru_cache_object *self)
1122{
1123 lru_list_elem *list = lru_cache_unlink_list(self);
1124 Py_CLEAR(self->maxsize_O);
1125 Py_CLEAR(self->func);
1126 Py_CLEAR(self->cache);
1127 Py_CLEAR(self->cache_info_type);
1128 Py_CLEAR(self->dict);
1129 lru_cache_clear_list(list);
1130 return 0;
1131}
1132
1133
1134PyDoc_STRVAR(lru_cache_doc,
1135"Create a cached callable that wraps another function.\n\
1136\n\
1137user_function: the function being cached\n\
1138\n\
1139maxsize: 0 for no caching\n\
1140 None for unlimited cache size\n\
1141 n for a bounded cache\n\
1142\n\
1143typed: False cache f(3) and f(3.0) as identical calls\n\
1144 True cache f(3) and f(3.0) as distinct calls\n\
1145\n\
1146cache_info_type: namedtuple class with the fields:\n\
1147 hits misses currsize maxsize\n"
1148);
1149
1150static PyMethodDef lru_cache_methods[] = {
1151 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1152 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
Serhiy Storchaka45120f22015-10-24 09:49:56 +03001153 {"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
Serhiy Storchakae4d65e32015-12-28 23:58:07 +02001154 {"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
1155 {"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001156 {NULL}
1157};
1158
1159static PyGetSetDef lru_cache_getsetlist[] = {
1160 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1161 {NULL}
1162};
1163
1164static PyTypeObject lru_cache_type = {
1165 PyVarObject_HEAD_INIT(NULL, 0)
1166 "functools._lru_cache_wrapper", /* tp_name */
1167 sizeof(lru_cache_object), /* tp_basicsize */
1168 0, /* tp_itemsize */
1169 /* methods */
1170 (destructor)lru_cache_dealloc, /* tp_dealloc */
1171 0, /* tp_print */
1172 0, /* tp_getattr */
1173 0, /* tp_setattr */
1174 0, /* tp_reserved */
1175 0, /* tp_repr */
1176 0, /* tp_as_number */
1177 0, /* tp_as_sequence */
1178 0, /* tp_as_mapping */
1179 0, /* tp_hash */
1180 (ternaryfunc)lru_cache_call, /* tp_call */
1181 0, /* tp_str */
1182 0, /* tp_getattro */
1183 0, /* tp_setattro */
1184 0, /* tp_as_buffer */
1185 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1186 /* tp_flags */
1187 lru_cache_doc, /* tp_doc */
1188 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1189 (inquiry)lru_cache_tp_clear, /* tp_clear */
1190 0, /* tp_richcompare */
1191 0, /* tp_weaklistoffset */
1192 0, /* tp_iter */
1193 0, /* tp_iternext */
1194 lru_cache_methods, /* tp_methods */
1195 0, /* tp_members */
1196 lru_cache_getsetlist, /* tp_getset */
1197 0, /* tp_base */
1198 0, /* tp_dict */
Serhiy Storchakae7070f02015-06-08 11:19:24 +03001199 lru_cache_descr_get, /* tp_descr_get */
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001200 0, /* tp_descr_set */
1201 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1202 0, /* tp_init */
1203 0, /* tp_alloc */
1204 lru_cache_new, /* tp_new */
1205};
1206
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001207/* module level code ********************************************************/
1208
1209PyDoc_STRVAR(module_doc,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001210"Tools that operate on functions.");
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001211
1212static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001213 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
Victor Stinner446c8d52011-04-05 12:21:35 +02001214 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1215 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001216 {NULL, NULL} /* sentinel */
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001217};
1218
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001219static void
1220module_free(void *m)
1221{
1222 Py_CLEAR(kwd_mark);
1223}
Martin v. Löwis1a214512008-06-11 05:26:20 +00001224
1225static struct PyModuleDef _functoolsmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001226 PyModuleDef_HEAD_INIT,
1227 "_functools",
1228 module_doc,
1229 -1,
1230 module_methods,
1231 NULL,
1232 NULL,
1233 NULL,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001234 module_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +00001235};
1236
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001237PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001238PyInit__functools(void)
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001239{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001240 int i;
1241 PyObject *m;
1242 char *name;
1243 PyTypeObject *typelist[] = {
1244 &partial_type,
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001245 &lru_cache_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001246 NULL
1247 };
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001248
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001249 m = PyModule_Create(&_functoolsmodule);
1250 if (m == NULL)
1251 return NULL;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001252
Serhiy Storchaka46c56112015-05-24 21:53:49 +03001253 kwd_mark = PyObject_CallObject((PyObject *)&PyBaseObject_Type, NULL);
1254 if (!kwd_mark) {
1255 Py_DECREF(m);
1256 return NULL;
1257 }
1258
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001259 for (i=0 ; typelist[i] != NULL ; i++) {
1260 if (PyType_Ready(typelist[i]) < 0) {
1261 Py_DECREF(m);
1262 return NULL;
1263 }
1264 name = strchr(typelist[i]->tp_name, '.');
1265 assert (name != NULL);
1266 Py_INCREF(typelist[i]);
1267 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1268 }
1269 return m;
Raymond Hettinger9c323f82005-02-28 19:39:44 +00001270}