Skip to content

Commit 1d80da9

Browse files
TeamTamoadyouknowone
authored andcommitted
Implement true hash for tuple
1 parent 3886f88 commit 1d80da9

File tree

2 files changed

+38
-6
lines changed

2 files changed

+38
-6
lines changed

Lib/test/test_tuple.py

-2
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ def f():
7777
# We expect tuples whose base components have deterministic hashes to
7878
# have deterministic hashes too - and, indeed, the same hashes across
7979
# platforms with hash codes of the same bit width.
80-
# TODO: RUSTPYTHON
81-
@unittest.expectedFailure
8280
def test_hash_exact(self):
8381
def check_one_exact(t, e32, e64):
8482
got = hash(t)

vm/src/builtins/tuple.rs

+38-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use once_cell::sync::Lazy;
22

33
use super::{PositionIterInternal, PyGenericAlias, PyType, PyTypeRef};
4-
use crate::common::{hash::PyHash, lock::PyMutex};
4+
use crate::common::{
5+
hash::{PyHash, PyUHash},
6+
lock::PyMutex,
7+
};
58
use crate::{
69
atomic_func,
710
class::PyClassImpl,
@@ -525,7 +528,38 @@ impl<T: TransmuteFromObject> ToPyObject for PyTupleTyped<T> {
525528
}
526529

527530
pub(super) fn tuple_hash(elements: &[PyObjectRef], vm: &VirtualMachine) -> PyResult<PyHash> {
528-
// TODO: See #3460 for the correct implementation.
529-
// https://github.com/RustPython/RustPython/pull/3460
530-
crate::utils::hash_iter(elements.iter(), vm)
531+
#[cfg(target_pointer_width = "64")]
532+
const PRIME1: PyUHash = 11400714785074694791;
533+
#[cfg(target_pointer_width = "64")]
534+
const PRIME2: PyUHash = 14029467366897019727;
535+
#[cfg(target_pointer_width = "64")]
536+
const PRIME5: PyUHash = 2870177450012600261;
537+
#[cfg(target_pointer_width = "64")]
538+
const ROTATE: u32 = 31;
539+
540+
#[cfg(target_pointer_width = "32")]
541+
const PRIME1: PyUHash = 2654435761;
542+
#[cfg(target_pointer_width = "32")]
543+
const PRIME2: PyUHash = 2246822519;
544+
#[cfg(target_pointer_width = "32")]
545+
const PRIME5: PyUHash = 374761393;
546+
#[cfg(target_pointer_width = "32")]
547+
const ROTATE: u32 = 13;
548+
549+
let mut acc = PRIME5;
550+
let len = elements.len() as PyUHash;
551+
552+
for val in elements {
553+
let lane = val.hash(vm)? as PyUHash;
554+
acc = acc.wrapping_add(lane.wrapping_mul(PRIME2));
555+
acc = acc.rotate_left(ROTATE);
556+
acc = acc.wrapping_mul(PRIME1);
557+
}
558+
559+
acc = acc.wrapping_add(len ^ (PRIME5 ^ 3527539));
560+
561+
if acc as PyHash == -1 {
562+
return Ok(1546275796);
563+
}
564+
Ok(acc as PyHash)
531565
}

0 commit comments

Comments
 (0)