From 4af77a027680f2aa956a4d1c50947d6e2dbd0185 Mon Sep 17 00:00:00 2001 From: Stefan Krah Date: Fri, 2 Nov 2012 17:49:22 +0100 Subject: [PATCH] Issue #15814: Use hash function that is compatible with the equality definition from #15573. --- Doc/library/stdtypes.rst | 6 ------ Lib/test/test_buffer.py | 32 ++++++++++++++++++++++++++++++-- Objects/memoryobject.c | 8 ++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 046295ca9f..ea6977f477 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2393,12 +2393,6 @@ copying. .. versionchanged:: 3.3 One-dimensional memoryviews with formats 'B', 'b' or 'c' are now hashable. - .. note:: - Hashing of memoryviews with formats other than 'B', 'b' or 'c' as well - as hashing of multi-dimensional memoryviews is possible in version 3.3.0, - but will raise an error in 3.3.1 in order to be compatible with the new - memoryview equality definition. - :class:`memoryview` has several methods: .. method:: __eq__(exporter) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 26cd9be30f..977b282d63 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -3999,14 +3999,42 @@ class TestBufferProtocol(unittest.TestCase): m = memoryview(x) self.assertEqual(hash(m), hash(x)) + # equality-hash invariant + x = ndarray(list(range(12)), shape=[12], format='B') + a = memoryview(nd) + + y = ndarray(list(range(12)), shape=[12], format='b') + b = memoryview(nd) + + z = ndarray(list(bytes(chr(x), 'latin-1') for x in range(12)), + shape=[12], format='c') + c = memoryview(nd) + + if (a == b): + self.assertEqual(hash(a), hash(b)) + + if (a == c): + self.assertEqual(hash(a), hash(c)) + + if (b == c): + self.assertEqual(hash(b), hash(c)) + # non-byte formats nd = ndarray(list(range(12)), shape=[2,2,3], format='L') m = memoryview(nd) - self.assertEqual(hash(m), hash(nd.tobytes())) + self.assertRaises(ValueError, m.__hash__) nd = ndarray(list(range(-6, 6)), shape=[2,2,3], format='h') m = memoryview(nd) - self.assertEqual(hash(m), hash(nd.tobytes())) + self.assertRaises(ValueError, m.__hash__) + + nd = ndarray(list(range(12)), shape=[2,2,3], format='= L') + m = memoryview(nd) + self.assertRaises(ValueError, m.__hash__) + + nd = ndarray(list(range(-6, 6)), shape=[2,2,3], format='< h') + m = memoryview(nd) + self.assertRaises(ValueError, m.__hash__) def test_memoryview_release(self): diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index d56faf87cc..dd6fe825ae 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -2707,6 +2707,8 @@ memory_hash(PyMemoryViewObject *self) if (self->hash == -1) { Py_buffer *view = &self->view; char *mem = view->buf; + Py_ssize_t ret; + char fmt; CHECK_RELEASED_INT(self); @@ -2715,6 +2717,12 @@ memory_hash(PyMemoryViewObject *self) "cannot hash writable memoryview object"); return -1; } + ret = get_native_fmtchar(&fmt, view->format); + if (ret < 0 || !IS_BYTE_FORMAT(fmt)) { + PyErr_SetString(PyExc_ValueError, + "memoryview: hashing is restricted to formats 'B', 'b' or 'c'"); + return -1; + } if (view->obj != NULL && PyObject_Hash(view->obj) == -1) { /* Keep the original error message */ return -1; -- 2.40.0