File: python-3.10.patch

package info (click to toggle)
tinyarray 1.2.3-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 368 kB
  • sloc: cpp: 2,811; python: 656; makefile: 12
file content (117 lines) | stat: -rw-r--r-- 4,066 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
From: Stefano Rivera <stefanor@debian.org>
Date: Mon, 22 Nov 2021 13:38:59 -0400
Subject: Python 3.10 Support

In Python 3.10, NaNs no longer hash equal, instead they are hashed by
their object's address. (See: https://bugs.python.org/issue43475)

Replace that behaviour by passing the address of the object to the
hash() function.

This is all rather messy, I'm sure someone more familiar with C++
templates can do something a lot tidier...

Bug-Upstream: https://gitlab.kwant-project.org/kwant/tinyarray/-/issues/20
Forwarded: https://gitlab.kwant-project.org/kwant/tinyarray/-/merge_requests/14
---
 src/array.cc      | 24 +++++++++++++++---------
 test_tinyarray.py |  2 +-
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/src/array.cc b/src/array.cc
index 12b700e..c4851c6 100644
--- a/src/array.cc
+++ b/src/array.cc
@@ -815,7 +815,7 @@ fail:
 // the only documentation for this is in the Python sourcecode
 const Py_hash_t HASH_IMAG = _PyHASH_IMAG;
 
-Py_hash_t hash(long x)
+Py_hash_t hash(void *inst, long x)
 {
     // For integers the hash is just the integer itself modulo _PyHASH_MODULUS
     // except for the singular case of -1.
@@ -834,24 +834,28 @@ typedef long Py_hash_t;
 typedef unsigned long Py_uhash_t;
 const Py_hash_t HASH_IMAG = 1000003L;
 
-Py_hash_t hash(long x)
+Py_hash_t hash(void *inst, long x)
 {
     return x != -1 ? x : -2;
 }
 
 #endif
 
-Py_hash_t hash(double x)
+Py_hash_t hash(void *inst, double x)
 {
     // We used to have our own implementation of this, but the extra function
     // call is quite negligible compared to the execution time of the function.
+#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 10
+    return _Py_HashDouble((PyObject *)inst, x);
+#else
     return _Py_HashDouble(x);
+#endif
 }
 
-Py_hash_t hash(Complex x)
+Py_hash_t hash(void *inst, Complex x)
 {
     // x.imag == 0  =>  hash(x.imag) == 0  =>  hash(x) == hash(x.real)
-    return hash(x.real()) + HASH_IMAG * hash(x.imag());
+    return hash(inst, x.real()) + HASH_IMAG * hash(inst, x.imag());
 }
 
 // The following routine calculates the hash of a multi-dimensional array.  The
@@ -875,7 +879,7 @@ Py_hash_t hash(PyObject *obj)
     Array<T> *self = reinterpret_cast<Array<T> *>(obj);
     self->ndim_shape(&ndim, &shape);
     T *p = self->data();
-    if (ndim == 0) return hash(*p);
+    if (ndim == 0) return hash(p, *p);
 
     const Py_uhash_t mult_init = 1000003, r_init = 0x345678;
     const Py_uhash_t mul_addend = 82520, r_addend = 97531;
@@ -891,7 +895,8 @@ Py_hash_t hash(PyObject *obj)
             --i[d];
             if (d == ndim) {
                 // Innermost loop body.
-                r[d] = (r[d] ^ hash(*p++)) * mult[d];
+                r[d] = (r[d] ^ hash(p, *p)) * mult[d];
+                p++;
                 mult[d] += mul_addend + 2 * i[d];
             } else {
                 // Entering a loop.
@@ -958,7 +963,7 @@ Py_hash_t hash(PyObject *obj)
     Array<T> *self = reinterpret_cast<Array<T> *>(obj);
     self->ndim_shape(&ndim, &shape);
     T *p = self->data();
-    if (ndim == 0) return hash(*p);
+    if (ndim == 0) return hash(p, *p);
 
     Py_ssize_t i[max_ndim];
     Py_uhash_t acc[max_ndim];
@@ -971,7 +976,8 @@ Py_hash_t hash(PyObject *obj)
         if (i[d]) {
             --i[d];
             if (d == ndim) {
-                _hash_inner_loop(acc[d], hash(*p++));
+                _hash_inner_loop(acc[d], hash(p, *p));
+                p++;
             } else {
                 ++d;
                 i[d] = shape[d];
diff --git a/test_tinyarray.py b/test_tinyarray.py
index ebacd4e..c78edf7 100644
--- a/test_tinyarray.py
+++ b/test_tinyarray.py
@@ -313,7 +313,7 @@ def test_hash_equality():
     int_bits = (8 * ta.dtype_size[int]) - 1  # 8 bits per byte, minus 1 sign bit
     maxint = 2**(int_bits)
 
-    special = [float('nan'), float('inf'), float('-inf'),
+    special = [float('inf'), float('-inf'),
                0, -1, -1.0, -1 + 0j,
                303, -312424, -0.3, 1.7, 0.4j, -12.3j, 1 - 12.3j, 1.3 - 12.3j,
                (), (-1,), (2,),