Implement true hash for tuple (#3460)

This commit is contained in:
Narawit Rakket
2025-06-27 12:27:27 +07:00
committed by GitHub
parent 5a81533f61
commit 2ea77b4442
2 changed files with 38 additions and 6 deletions

View File

@@ -77,8 +77,6 @@ class TupleTest(seq_tests.CommonTest):
# We expect tuples whose base components have deterministic hashes to
# have deterministic hashes too - and, indeed, the same hashes across
# platforms with hash codes of the same bit width.
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_hash_exact(self):
def check_one_exact(t, e32, e64):
got = hash(t)

View File

@@ -1,5 +1,8 @@
use super::{PositionIterInternal, PyGenericAlias, PyStrRef, PyType, PyTypeRef};
use crate::common::{hash::PyHash, lock::PyMutex};
use crate::common::{
hash::{PyHash, PyUHash},
lock::PyMutex,
};
use crate::object::{Traverse, TraverseFn};
use crate::{
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
@@ -589,7 +592,38 @@ impl<T: TransmuteFromObject> ToPyObject for PyTupleTyped<T> {
}
pub(super) fn tuple_hash(elements: &[PyObjectRef], vm: &VirtualMachine) -> PyResult<PyHash> {
// TODO: See #3460 for the correct implementation.
// https://github.com/RustPython/RustPython/pull/3460
crate::utils::hash_iter(elements.iter(), vm)
#[cfg(target_pointer_width = "64")]
const PRIME1: PyUHash = 11400714785074694791;
#[cfg(target_pointer_width = "64")]
const PRIME2: PyUHash = 14029467366897019727;
#[cfg(target_pointer_width = "64")]
const PRIME5: PyUHash = 2870177450012600261;
#[cfg(target_pointer_width = "64")]
const ROTATE: u32 = 31;
#[cfg(target_pointer_width = "32")]
const PRIME1: PyUHash = 2654435761;
#[cfg(target_pointer_width = "32")]
const PRIME2: PyUHash = 2246822519;
#[cfg(target_pointer_width = "32")]
const PRIME5: PyUHash = 374761393;
#[cfg(target_pointer_width = "32")]
const ROTATE: u32 = 13;
let mut acc = PRIME5;
let len = elements.len() as PyUHash;
for val in elements {
let lane = val.hash(vm)? as PyUHash;
acc = acc.wrapping_add(lane.wrapping_mul(PRIME2));
acc = acc.rotate_left(ROTATE);
acc = acc.wrapping_mul(PRIME1);
}
acc = acc.wrapping_add(len ^ (PRIME5 ^ 3527539));
if acc as PyHash == -1 {
return Ok(1546275796);
}
Ok(acc as PyHash)
}