]> granicus.if.org Git - python/commitdiff
Issue #15814: Use hash function that is compatible with the equality
authorStefan Krah <skrah@bytereef.org>
Fri, 2 Nov 2012 16:49:22 +0000 (17:49 +0100)
committerStefan Krah <skrah@bytereef.org>
Fri, 2 Nov 2012 16:49:22 +0000 (17:49 +0100)
definition from #15573.

Doc/library/stdtypes.rst
Lib/test/test_buffer.py
Objects/memoryobject.c

index 046295ca9f7c690dedfd05a66c66d2742c41046c..ea6977f4773bd26942f1aeaa12411e3d6227cda2 100644 (file)
@@ -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)
index 26cd9be30f3168493b1ee3bc9fe7b501bebe5943..977b282d636d242b86ad139fe112ebfb245800bf 100644 (file)
@@ -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):
 
index d56faf87cc427648d5a04196ccf6a4a40603056e..dd6fe825aef77ee3cfc181a2722f621371319009 100644 (file)
@@ -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;