From 1a0abdbc9986efa7f054e4e16b5a1d0329e8bca3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 18:52:35 +0200 Subject: keyobject_richcompare() now uses fast call Issue #27128: keyobject_richcompare() now calls _PyObject_FastCall() using a small stack allocated on the C stack to avoid a temporary tuple. --- Modules/_functoolsmodule.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'Modules/_functoolsmodule.c') diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index d785c4932b..f7dbf15ab3 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -461,12 +461,12 @@ static PyObject * keyobject_richcompare(PyObject *ko, PyObject *other, int op) { PyObject *res; - PyObject *args; PyObject *x; PyObject *y; PyObject *compare; PyObject *answer; static PyObject *zero; + PyObject* stack[2]; if (zero == NULL) { zero = PyLong_FromLong(0); @@ -490,17 +490,13 @@ keyobject_richcompare(PyObject *ko, PyObject *other, int op) /* Call the user's comparison function and translate the 3-way * result into true or false (or error). */ - args = PyTuple_New(2); - if (args == NULL) - return NULL; - Py_INCREF(x); - Py_INCREF(y); - PyTuple_SET_ITEM(args, 0, x); - PyTuple_SET_ITEM(args, 1, y); - res = PyObject_Call(compare, args, NULL); - Py_DECREF(args); - if (res == NULL) + stack[0] = x; + stack[1] = y; + res = _PyObject_FastCall(compare, stack, 2, NULL); + if (res == NULL) { return NULL; + } + answer = PyObject_RichCompare(res, zero, op); Py_DECREF(res); return answer; -- cgit v1.2.1 From de03c6d8066496680a1ea99ff9e67e28852b0007 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 22 Aug 2016 22:48:54 +0200 Subject: Rename _PyObject_FastCall() to _PyObject_FastCallDict() Issue #27809: * Rename _PyObject_FastCall() function to _PyObject_FastCallDict() * Add _PyObject_FastCall(), _PyObject_CallNoArg() and _PyObject_CallArg1() macros calling _PyObject_FastCallDict() --- Modules/_functoolsmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_functoolsmodule.c') diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index f7dbf15ab3..22e8088890 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -492,7 +492,7 @@ keyobject_richcompare(PyObject *ko, PyObject *other, int op) */ stack[0] = x; stack[1] = y; - res = _PyObject_FastCall(compare, stack, 2, NULL); + res = _PyObject_FastCall(compare, stack, 2); if (res == NULL) { return NULL; } -- cgit v1.2.1 From da9d0a5d894b1d4bdb0ed10d97656cdc3250c885 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 23 Aug 2016 16:22:35 +0200 Subject: Issue #27809: partial_call() uses fast call for positional args --- Modules/_functoolsmodule.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) (limited to 'Modules/_functoolsmodule.c') diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 22e8088890..848a03cb07 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -128,44 +128,60 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kw) { PyObject *ret; PyObject *argappl, *kwappl; + PyObject **stack; + Py_ssize_t nargs; assert (PyCallable_Check(pto->fn)); assert (PyTuple_Check(pto->args)); assert (PyDict_Check(pto->kw)); if (PyTuple_GET_SIZE(pto->args) == 0) { - argappl = args; - Py_INCREF(args); - } else if (PyTuple_GET_SIZE(args) == 0) { - argappl = pto->args; - Py_INCREF(pto->args); - } else { + stack = &PyTuple_GET_ITEM(args, 0); + nargs = PyTuple_GET_SIZE(args); + argappl = NULL; + } + else if (PyTuple_GET_SIZE(args) == 0) { + stack = &PyTuple_GET_ITEM(pto->args, 0); + nargs = PyTuple_GET_SIZE(pto->args); + argappl = NULL; + } + else { + stack = NULL; argappl = PySequence_Concat(pto->args, args); - if (argappl == NULL) + if (argappl == NULL) { return NULL; + } + assert(PyTuple_Check(argappl)); } if (PyDict_Size(pto->kw) == 0) { kwappl = kw; Py_XINCREF(kwappl); - } else { + } + else { kwappl = PyDict_Copy(pto->kw); if (kwappl == NULL) { - Py_DECREF(argappl); + Py_XDECREF(argappl); return NULL; } + if (kw != NULL) { if (PyDict_Merge(kwappl, kw, 1) != 0) { - Py_DECREF(argappl); + Py_XDECREF(argappl); Py_DECREF(kwappl); return NULL; } } } - ret = PyObject_Call(pto->fn, argappl, kwappl); - Py_DECREF(argappl); + if (stack) { + ret = _PyObject_FastCallDict(pto->fn, stack, nargs, kwappl); + } + else { + ret = PyObject_Call(pto->fn, argappl, kwappl); + Py_DECREF(argappl); + } Py_XDECREF(kwappl); return ret; } -- cgit v1.2.1 From c82774eb054aaaf80c65e2dd72c56b5d4735993b Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sat, 10 Sep 2016 20:00:02 +1000 Subject: Issue #27137: align Python & C implementations of functools.partial The pure Python fallback implementation of functools.partial now matches the behaviour of its accelerated C counterpart for subclassing, pickling and text representation purposes. Patch by Emanuel Barry and Serhiy Storchaka. --- Modules/_functoolsmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_functoolsmodule.c') diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 848a03cb07..fa5fad3e75 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -229,7 +229,7 @@ partial_repr(partialobject *pto) if (status != 0) { if (status < 0) return NULL; - return PyUnicode_FromFormat("%s(...)", Py_TYPE(pto)->tp_name); + return PyUnicode_FromString("..."); } arglist = PyUnicode_FromString(""); -- cgit v1.2.1 From 01a053991ffed3ca4a8cb22838b36782df70629f Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 8 Jan 2017 17:28:20 -0800 Subject: Issue #29203: functools.lru_cache() now respects PEP 468 --- Modules/_functoolsmodule.c | 49 +++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) (limited to 'Modules/_functoolsmodule.c') diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 2269d05da8..ca61fcd8b0 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -704,8 +704,8 @@ static PyTypeObject lru_cache_type; static PyObject * lru_cache_make_key(PyObject *args, PyObject *kwds, int typed) { - PyObject *key, *sorted_items; - Py_ssize_t key_size, pos, key_pos; + PyObject *key, *keyword, *value; + Py_ssize_t key_size, pos, key_pos, kwds_size; /* short path, key will match args anyway, which is a tuple */ if (!typed && !kwds) { @@ -713,28 +713,18 @@ lru_cache_make_key(PyObject *args, PyObject *kwds, int typed) return args; } - if (kwds && PyDict_Size(kwds) > 0) { - sorted_items = PyDict_Items(kwds); - if (!sorted_items) - return NULL; - if (PyList_Sort(sorted_items) < 0) { - Py_DECREF(sorted_items); - return NULL; - } - } else - sorted_items = NULL; + kwds_size = kwds ? PyDict_Size(kwds) : 0; + assert(kwds_size >= 0); key_size = PyTuple_GET_SIZE(args); - if (sorted_items) - key_size += PyList_GET_SIZE(sorted_items); + if (kwds_size) + key_size += kwds_size * 2 + 1; if (typed) - key_size *= 2; - if (sorted_items) - key_size++; + key_size += PyTuple_GET_SIZE(args) + kwds_size; key = PyTuple_New(key_size); if (key == NULL) - goto done; + return NULL; key_pos = 0; for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) { @@ -742,14 +732,16 @@ lru_cache_make_key(PyObject *args, PyObject *kwds, int typed) Py_INCREF(item); PyTuple_SET_ITEM(key, key_pos++, item); } - if (sorted_items) { + if (kwds_size) { Py_INCREF(kwd_mark); PyTuple_SET_ITEM(key, key_pos++, kwd_mark); - for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) { - PyObject *item = PyList_GET_ITEM(sorted_items, pos); - Py_INCREF(item); - PyTuple_SET_ITEM(key, key_pos++, item); + for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) { + Py_INCREF(keyword); + PyTuple_SET_ITEM(key, key_pos++, keyword); + Py_INCREF(value); + PyTuple_SET_ITEM(key, key_pos++, value); } + assert(key_pos == PyTuple_GET_SIZE(args) + kwds_size * 2 + 1); } if (typed) { for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) { @@ -757,20 +749,15 @@ lru_cache_make_key(PyObject *args, PyObject *kwds, int typed) Py_INCREF(item); PyTuple_SET_ITEM(key, key_pos++, item); } - if (sorted_items) { - for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) { - PyObject *tp_items = PyList_GET_ITEM(sorted_items, pos); - PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(tp_items, 1)); + if (kwds_size) { + for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) { + PyObject *item = (PyObject *)Py_TYPE(value); Py_INCREF(item); PyTuple_SET_ITEM(key, key_pos++, item); } } } assert(key_pos == key_size); - -done: - if (sorted_items) - Py_DECREF(sorted_items); return key; } -- cgit v1.2.1