mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Support slice hash (#5123)
* make slice object hashable * Update test_slice.py from CPython v3.12 * remove TODO * remove outdated tests
This commit is contained in:
52
Lib/test/test_slice.py
vendored
52
Lib/test/test_slice.py
vendored
@@ -5,6 +5,7 @@ import operator
|
||||
import sys
|
||||
import unittest
|
||||
import weakref
|
||||
import copy
|
||||
|
||||
from pickle import loads, dumps
|
||||
from test import support
|
||||
@@ -79,10 +80,16 @@ class SliceTest(unittest.TestCase):
|
||||
self.assertEqual(repr(slice(1, 2, 3)), "slice(1, 2, 3)")
|
||||
|
||||
def test_hash(self):
|
||||
# Verify clearing of SF bug #800796
|
||||
self.assertRaises(TypeError, hash, slice(5))
|
||||
self.assertEqual(hash(slice(5)), slice(5).__hash__())
|
||||
self.assertEqual(hash(slice(1, 2)), slice(1, 2).__hash__())
|
||||
self.assertEqual(hash(slice(1, 2, 3)), slice(1, 2, 3).__hash__())
|
||||
self.assertNotEqual(slice(5), slice(6))
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
slice(5).__hash__()
|
||||
hash(slice(1, 2, []))
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
hash(slice(4, {}))
|
||||
|
||||
def test_cmp(self):
|
||||
s1 = slice(1, 2, 3)
|
||||
@@ -235,13 +242,50 @@ class SliceTest(unittest.TestCase):
|
||||
self.assertEqual(tmp, [(slice(1, 2), 42)])
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
s = slice(10, 20, 3)
|
||||
for protocol in (0,1,2):
|
||||
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
t = loads(dumps(s, protocol))
|
||||
self.assertEqual(s, t)
|
||||
self.assertEqual(s.indices(15), t.indices(15))
|
||||
self.assertNotEqual(id(s), id(t))
|
||||
|
||||
def test_copy(self):
|
||||
s = slice(1, 10)
|
||||
c = copy.copy(s)
|
||||
self.assertIs(s, c)
|
||||
|
||||
s = slice(1, 10, 2)
|
||||
c = copy.copy(s)
|
||||
self.assertIs(s, c)
|
||||
|
||||
# Corner case for mutable indices:
|
||||
s = slice([1, 2], [3, 4], [5, 6])
|
||||
c = copy.copy(s)
|
||||
self.assertIs(s, c)
|
||||
self.assertIs(s.start, c.start)
|
||||
self.assertIs(s.stop, c.stop)
|
||||
self.assertIs(s.step, c.step)
|
||||
|
||||
def test_deepcopy(self):
|
||||
s = slice(1, 10)
|
||||
c = copy.deepcopy(s)
|
||||
self.assertEqual(s, c)
|
||||
|
||||
s = slice(1, 10, 2)
|
||||
c = copy.deepcopy(s)
|
||||
self.assertEqual(s, c)
|
||||
|
||||
# Corner case for mutable indices:
|
||||
s = slice([1, 2], [3, 4], [5, 6])
|
||||
c = copy.deepcopy(s)
|
||||
self.assertIsNot(s, c)
|
||||
self.assertEqual(s, c)
|
||||
self.assertIsNot(s.start, c.start)
|
||||
self.assertIsNot(s.stop, c.stop)
|
||||
self.assertIsNot(s.step, c.step)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_cycle(self):
|
||||
|
||||
@@ -82,16 +82,6 @@ assert_raises(TypeError, lambda: slice(0) > 3)
|
||||
assert_raises(TypeError, lambda: slice(0) <= 3)
|
||||
assert_raises(TypeError, lambda: slice(0) >= 3)
|
||||
|
||||
# TODO: slice is hashable in CPython 3.12
|
||||
# assert_raises(TypeError, hash, slice(0))
|
||||
# assert_raises(TypeError, hash, slice(None))
|
||||
#
|
||||
# def dict_slice():
|
||||
# d = {}
|
||||
# d[slice(0)] = 3
|
||||
#
|
||||
# assert_raises(TypeError, dict_slice)
|
||||
|
||||
assert slice(None ).indices(10) == (0, 10, 1)
|
||||
assert slice(None, None, 2).indices(10) == (0, 10, 2)
|
||||
assert slice(1, None, 2).indices(10) == (1, 10, 2)
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
use super::{PyStrRef, PyTupleRef, PyType, PyTypeRef};
|
||||
use crate::{
|
||||
class::PyClassImpl,
|
||||
common::hash::{PyHash, PyUHash},
|
||||
convert::ToPyObject,
|
||||
function::{ArgIndex, FuncArgs, OptionalArg, PyComparisonValue},
|
||||
sliceable::SaturatedSlice,
|
||||
types::{Comparable, Constructor, PyComparisonOp, Representable},
|
||||
types::{Comparable, Constructor, Hashable, PyComparisonOp, Representable},
|
||||
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
use malachite_bigint::{BigInt, ToBigInt};
|
||||
@@ -26,7 +27,7 @@ impl PyPayload for PySlice {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(with(Comparable, Representable))]
|
||||
#[pyclass(with(Comparable, Representable, Hashable))]
|
||||
impl PySlice {
|
||||
#[pygetset]
|
||||
fn start(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
@@ -197,6 +198,47 @@ impl PySlice {
|
||||
}
|
||||
}
|
||||
|
||||
impl Hashable for PySlice {
|
||||
#[inline]
|
||||
fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyHash> {
|
||||
const XXPRIME_1: PyUHash = if cfg!(target_pointer_width = "64") {
|
||||
11400714785074694791
|
||||
} else {
|
||||
2654435761
|
||||
};
|
||||
const XXPRIME_2: PyUHash = if cfg!(target_pointer_width = "64") {
|
||||
14029467366897019727
|
||||
} else {
|
||||
2246822519
|
||||
};
|
||||
const XXPRIME_5: PyUHash = if cfg!(target_pointer_width = "64") {
|
||||
2870177450012600261
|
||||
} else {
|
||||
374761393
|
||||
};
|
||||
const ROTATE: u32 = if cfg!(target_pointer_width = "64") {
|
||||
31
|
||||
} else {
|
||||
13
|
||||
};
|
||||
|
||||
let mut acc = XXPRIME_5;
|
||||
for part in [zelf.start_ref(vm), &zelf.stop, zelf.step_ref(vm)].iter() {
|
||||
let lane = part.hash(vm)? as PyUHash;
|
||||
if lane == u64::MAX as PyUHash {
|
||||
return Ok(-1 as PyHash);
|
||||
}
|
||||
acc = acc.wrapping_add(lane.wrapping_mul(XXPRIME_2));
|
||||
acc = acc.rotate_left(ROTATE);
|
||||
acc = acc.wrapping_mul(XXPRIME_1);
|
||||
}
|
||||
if acc == u64::MAX as PyUHash {
|
||||
return Ok(1546275796 as PyHash);
|
||||
}
|
||||
Ok(acc as PyHash)
|
||||
}
|
||||
}
|
||||
|
||||
impl Comparable for PySlice {
|
||||
fn cmp(
|
||||
zelf: &Py<Self>,
|
||||
|
||||
Reference in New Issue
Block a user