diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2011-11-21 19:46:33 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2011-11-21 19:46:33 (GMT) |
commit | ce4a9da70535b4bb9048147b141f01004af2133d (patch) | |
tree | 853fa7484683a9c858f29bfab1320fb4baee5d98 /Objects | |
parent | 0a3229de6b80cfa9e432ef5a9c72548569503075 (diff) | |
download | cpython-ce4a9da70535b4bb9048147b141f01004af2133d.zip cpython-ce4a9da70535b4bb9048147b141f01004af2133d.tar.gz cpython-ce4a9da70535b4bb9048147b141f01004af2133d.tar.bz2 |
Issue #13411: memoryview objects are now hashable when the underlying object is hashable.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/bytesobject.c | 21 | ||||
-rw-r--r-- | Objects/memoryobject.c | 34 | ||||
-rw-r--r-- | Objects/object.c | 15 |
3 files changed, 53 insertions, 17 deletions
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index a89798a..88411b7 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -860,22 +860,11 @@ bytes_richcompare(PyBytesObject *a, PyBytesObject *b, int op) static Py_hash_t bytes_hash(PyBytesObject *a) { - register Py_ssize_t len; - register unsigned char *p; - register Py_uhash_t x; - - if (a->ob_shash != -1) - return a->ob_shash; - len = Py_SIZE(a); - p = (unsigned char *) a->ob_sval; - x = (Py_uhash_t)*p << 7; - while (--len >= 0) - x = (1000003U*x) ^ (Py_uhash_t)*p++; - x ^= (Py_uhash_t)Py_SIZE(a); - if (x == -1) - x = -2; - a->ob_shash = x; - return x; + if (a->ob_shash == -1) { + /* Can't fail */ + a->ob_shash = _Py_HashBytes((unsigned char *) a->ob_sval, Py_SIZE(a)); + } + return a->ob_shash; } static PyObject* diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index e0d1a89..295a742 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -84,6 +84,7 @@ PyMemoryView_FromBuffer(Py_buffer *info) PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type); if (mview == NULL) return NULL; + mview->hash = -1; dup_buffer(&mview->view, info); /* NOTE: mview->view.obj should already have been incref'ed as part of PyBuffer_FillInfo(). */ @@ -512,6 +513,37 @@ memory_repr(PyMemoryViewObject *self) return PyUnicode_FromFormat("<memory at %p>", self); } +static Py_hash_t +memory_hash(PyMemoryViewObject *self) +{ + if (self->hash == -1) { + Py_buffer *view = &self->view; + CHECK_RELEASED_INT(self); + if (view->ndim > 1) { + PyErr_SetString(PyExc_NotImplementedError, + "can't hash multi-dimensional memoryview object"); + return -1; + } + if (view->strides && view->strides[0] != view->itemsize) { + PyErr_SetString(PyExc_NotImplementedError, + "can't hash strided memoryview object"); + return -1; + } + if (!view->readonly) { + PyErr_SetString(PyExc_ValueError, + "can't hash writable memoryview object"); + return -1; + } + if (view->obj != NULL && PyObject_Hash(view->obj) == -1) { + /* Keep the original error message */ + return -1; + } + /* Can't fail */ + self->hash = _Py_HashBytes((unsigned char *) view->buf, view->len); + } + return self->hash; +} + /* Sequence methods */ static Py_ssize_t memory_length(PyMemoryViewObject *self) @@ -829,7 +861,7 @@ PyTypeObject PyMemoryView_Type = { 0, /* tp_as_number */ &memory_as_sequence, /* tp_as_sequence */ &memory_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)memory_hash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ diff --git a/Objects/object.c b/Objects/object.c index 25e64e1..00f1716 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -744,6 +744,21 @@ _Py_HashPointer(void *p) } Py_hash_t +_Py_HashBytes(unsigned char *p, Py_ssize_t len) +{ + Py_uhash_t x; + Py_ssize_t i; + + x = (Py_uhash_t) *p << 7; + for (i = 0; i < len; i++) + x = (1000003U * x) ^ (Py_uhash_t) *p++; + x ^= (Py_uhash_t) len; + if (x == -1) + x = -2; + return x; +} + +Py_hash_t PyObject_HashNotImplemented(PyObject *v) { PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", |