Skip to content

Commit c2cfff1

Browse files
committed
Adopt new Python 3.8 tuple.__hash__ algo for Record.__hash__
1 parent ddafaa5 commit c2cfff1

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

asyncpg/protocol/record/recordobj.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,48 @@ record_length(ApgRecordObject *o)
115115
}
116116

117117

118+
#if PY_VERSION_HEX >= 0x03080000
119+
120+
#if SIZEOF_PY_UHASH_T > 4
121+
#define _PyHASH_XXPRIME_1 ((Py_uhash_t)11400714785074694791ULL)
122+
#define _PyHASH_XXPRIME_2 ((Py_uhash_t)14029467366897019727ULL)
123+
#define _PyHASH_XXPRIME_5 ((Py_uhash_t)2870177450012600261ULL)
124+
#define _PyHASH_XXROTATE(x) ((x << 31) | (x >> 33)) /* Rotate left 31 bits */
125+
#else
126+
#define _PyHASH_XXPRIME_1 ((Py_uhash_t)2654435761UL)
127+
#define _PyHASH_XXPRIME_2 ((Py_uhash_t)2246822519UL)
128+
#define _PyHASH_XXPRIME_5 ((Py_uhash_t)374761393UL)
129+
#define _PyHASH_XXROTATE(x) ((x << 13) | (x >> 19)) /* Rotate left 13 bits */
130+
#endif
131+
132+
static Py_hash_t
133+
record_hash(ApgRecordObject *v)
134+
{
135+
Py_ssize_t i;
136+
Py_uhash_t acc = _PyHASH_XXPRIME_5;
137+
Py_ssize_t len = Py_SIZE(v);
138+
PyObject **els = v->ob_item;
139+
for (i = 0; i < len; i++) {
140+
Py_uhash_t lane = PyObject_Hash(els[i]);
141+
if (lane == (Py_uhash_t)-1) {
142+
return -1;
143+
}
144+
acc += lane * _PyHASH_XXPRIME_2;
145+
acc = _PyHASH_XXROTATE(acc);
146+
acc *= _PyHASH_XXPRIME_1;
147+
}
148+
149+
/* Add input length, mangled to keep the historical value of hash(()). */
150+
acc += len ^ (_PyHASH_XXPRIME_5 ^ 3527539UL);
151+
152+
if (acc == (Py_uhash_t)-1) {
153+
return 1546275796;
154+
}
155+
return (Py_hash_t)acc;
156+
}
157+
158+
#else
159+
118160
static Py_hash_t
119161
record_hash(ApgRecordObject *v)
120162
{
@@ -150,6 +192,8 @@ record_hash(ApgRecordObject *v)
150192
return (Py_hash_t)x;
151193
}
152194

195+
#endif
196+
153197

154198
static PyObject *
155199
record_richcompare(PyObject *v, PyObject *w, int op)

0 commit comments

Comments
 (0)