From 128517bb4a044b70cca7bfddb5ea9894e4a01be5 Mon Sep 17 00:00:00 2001 From: da-woods Date: Sun, 12 Jun 2022 16:20:57 +0100 Subject: [PATCH 1/2] Create fast version of match_keys for exact dict When the type is an exact dict, there's a real speed-up to be gained by skipping the call to "get" and using PyDict_GetItemWithError instead. --- Python/ceval.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/Python/ceval.c b/Python/ceval.c index 0e8186347cd8957..867882baa88b524 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -906,6 +906,58 @@ static const binaryfunc binary_ops[] = { // PEP 634: Structural Pattern Matching +// Faster version of match_keys (below) that works on a dict instead of +// a generic mapping +static PyObject* +match_keys_exactdict(PyThreadState *tstate, PyObject *map, PyObject *keys, Py_ssize_t nkeys) +{ + PyObject *seen = NULL; + PyObject *values = NULL; + seen = PySet_New(NULL); + if (seen == NULL) { + goto fail; + } + values = PyTuple_New(nkeys); + if (values == NULL) { + goto fail; + } + for (Py_ssize_t i = 0; i < nkeys; i++) { + PyObject *key = PyTuple_GET_ITEM(keys, i); + if (PySet_Contains(seen, key) || PySet_Add(seen, key)) { + if (!_PyErr_Occurred(tstate)) { + // Seen it before! + _PyErr_Format(tstate, PyExc_ValueError, + "mapping pattern checks duplicate key (%R)", key); + } + goto fail; + } + PyObject *value = PyDict_GetItemWithError(map, key); + if (value == NULL) { + if (_PyErr_Occurred(tstate)) { + goto fail; + } else { + // key not in map! + Py_DECREF(values); + // Return None: + Py_INCREF(Py_None); + values = Py_None; + goto done; + } + } + Py_INCREF(value); + PyTuple_SET_ITEM(values, i, value); + } + // Success: +done: + Py_DECREF(seen); + return values; +fail: + Py_XDECREF(seen); + Py_XDECREF(values); + return NULL; +} + + // Return a tuple of values corresponding to keys, with error checks for // duplicate/missing keys. static PyObject* @@ -917,6 +969,9 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) // No keys means no items. return PyTuple_New(0); } + if (PyDict_CheckExact(map)) { + return match_keys_exactdict(tstate, map, keys, nkeys); + } PyObject *seen = NULL; PyObject *dummy = NULL; PyObject *values = NULL; From 0996d525232b495c56cfb3bd9fd0d84cb8174e65 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 12 Jun 2022 15:32:56 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2022-06-12-15-32-55.gh-issue-93714.bW84XJ.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-06-12-15-32-55.gh-issue-93714.bW84XJ.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-12-15-32-55.gh-issue-93714.bW84XJ.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-12-15-32-55.gh-issue-93714.bW84XJ.rst new file mode 100644 index 000000000000000..39ddc67fd38b7ea --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-12-15-32-55.gh-issue-93714.bW84XJ.rst @@ -0,0 +1 @@ +Optimize pattern matching of mappings when the mapping is a builtin dictionary.