summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2015-10-02 09:47:59 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2015-10-02 09:47:59 (GMT)
commit5dbe245ef238762c8e1100885e8671bf2e089157 (patch)
treefdbbc3e62591f49891469af452f03d55681e76a7 /Modules
parent30b7138fe12be2896a53993b308664fddbe32a3a (diff)
parentb9d98d532cb9bdebff9854eaff91fea13769a595 (diff)
downloadcpython-5dbe245ef238762c8e1100885e8671bf2e089157.zip
cpython-5dbe245ef238762c8e1100885e8671bf2e089157.tar.gz
cpython-5dbe245ef238762c8e1100885e8671bf2e089157.tar.bz2
Issue #24483: C implementation of functools.lru_cache() now calculates key's
hash only once.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_functoolsmodule.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index dc64cfe..1f98067 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -601,6 +601,7 @@ struct lru_cache_object;
typedef struct lru_list_elem {
PyObject_HEAD
struct lru_list_elem *prev, *next; /* borrowed links */
+ Py_hash_t hash;
PyObject *key, *result;
} lru_list_elem;
@@ -762,10 +763,14 @@ static PyObject *
infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds)
{
PyObject *result;
+ Py_hash_t hash;
PyObject *key = lru_cache_make_key(args, kwds, self->typed);
if (!key)
return NULL;
- result = PyDict_GetItemWithError(self->cache, key);
+ hash = PyObject_Hash(key);
+ if (hash == -1)
+ return NULL;
+ result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
if (result) {
Py_INCREF(result);
self->hits++;
@@ -781,7 +786,7 @@ infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd
Py_DECREF(key);
return NULL;
}
- if (PyDict_SetItem(self->cache, key, result) < 0) {
+ if (_PyDict_SetItem_KnownHash(self->cache, key, result, hash) < 0) {
Py_DECREF(result);
Py_DECREF(key);
return NULL;
@@ -813,11 +818,15 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
{
lru_list_elem *link;
PyObject *key, *result;
+ Py_hash_t hash;
key = lru_cache_make_key(args, kwds, self->typed);
if (!key)
return NULL;
- link = (lru_list_elem *)PyDict_GetItemWithError(self->cache, key);
+ hash = PyObject_Hash(key);
+ if (hash == -1)
+ return NULL;
+ link = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
if (link) {
lru_cache_extricate_link(link);
lru_cache_append_link(self, link);
@@ -845,7 +854,8 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
/* Remove it from the cache.
The cache dict holds one reference to the link,
and the linked list holds yet one reference to it. */
- if (PyDict_DelItem(self->cache, link->key) < 0) {
+ if (_PyDict_DelItem_KnownHash(self->cache, link->key,
+ link->hash) < 0) {
lru_cache_append_link(self, link);
Py_DECREF(key);
Py_DECREF(result);
@@ -859,9 +869,11 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
oldkey = link->key;
oldresult = link->result;
+ link->hash = hash;
link->key = key;
link->result = result;
- if (PyDict_SetItem(self->cache, key, (PyObject *)link) < 0) {
+ if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
+ hash) < 0) {
Py_DECREF(link);
Py_DECREF(oldkey);
Py_DECREF(oldresult);
@@ -881,10 +893,12 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
return NULL;
}
+ link->hash = hash;
link->key = key;
link->result = result;
_PyObject_GC_TRACK(link);
- if (PyDict_SetItem(self->cache, key, (PyObject *)link) < 0) {
+ if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link,
+ hash) < 0) {
Py_DECREF(link);
return NULL;
}