Merge pull request #1487 from HyeockJinKim/issue1482

Fixed __hash__ of range
This commit is contained in:
Windel Bouwman
2019-10-07 19:40:48 +02:00
committed by GitHub
2 changed files with 43 additions and 15 deletions

View File

@@ -113,3 +113,15 @@ assert range(10)[-2:4] == range(8, 4)
assert range(10)[-6:-2] == range(4, 8)
assert range(50, 0, -2)[-5] == 10
assert range(50, 0, -2)[-5:3:5] == range(10, 44, -10)
assert hash(range(10)) == hash((10, 0, 1))
assert hash(range(10)) == hash(range(10))
assert hash(range(100)[20:30]) == hash(range(20, 30))
assert hash(range(10, 10)) == hash(range(0, 0))
assert hash(range(1, 2, 100)) == hash(range(1, 6, 100))
a = {}
for i in range(100):
a[range(10)] = 1
assert len(a.keys()) == 1

View File

@@ -5,6 +5,7 @@ use num_integer::Integer;
use num_traits::{One, Signed, Zero};
use crate::function::{OptionalArg, PyFuncArgs};
use crate::pyhash;
use crate::pyobject::{
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
};
@@ -75,18 +76,13 @@ impl PyRange {
#[inline]
pub fn get(&self, index: &BigInt) -> Option<BigInt> {
let start = self.start.as_bigint();
let stop = self.stop.as_bigint();
let step = self.step.as_bigint();
let index = index.clone();
if self.is_empty() {
return None;
}
let length: BigInt = if start < stop {
(stop - start - 1) / step + 1
} else {
(start - stop - 1) / (-step) + 1
};
let length = self.length();
let index = if index.is_negative() {
let new_index: BigInt = &length + &index;
@@ -106,15 +102,15 @@ impl PyRange {
}
#[inline]
fn length(&self) -> PyInt {
fn length(&self) -> BigInt {
let start = self.start.as_bigint();
let stop = self.stop.as_bigint();
let step = self.step.as_bigint();
match step.sign() {
Sign::Plus if start < stop => PyInt::new((stop - start - 1usize) / step + 1),
Sign::Minus if start > stop => PyInt::new((start - stop - 1usize) / (-step) + 1),
Sign::Plus | Sign::Minus => PyInt::new(0),
Sign::Plus if start < stop => (stop - start - 1usize) / step + 1,
Sign::Minus if start > stop => (start - stop - 1usize) / (-step) + 1,
Sign::Plus | Sign::Minus => BigInt::zero(),
Sign::NoSign => unreachable!(),
}
}
@@ -214,7 +210,7 @@ impl PyRange {
#[pymethod(name = "__len__")]
fn len(&self, _vm: &VirtualMachine) -> PyInt {
self.length()
PyInt::new(self.length())
}
#[pymethod(name = "__repr__")]
@@ -248,11 +244,11 @@ impl PyRange {
if objtype::isinstance(&rhs, &vm.ctx.range_type()) {
let rhs = get_value(&rhs);
if self.length().as_bigint() != rhs.length().as_bigint() {
if self.length() != rhs.length() {
return false;
}
if self.length().as_bigint().is_zero() {
if self.length().is_zero() {
return true;
}
@@ -321,8 +317,7 @@ impl PyRange {
RangeIndex::Slice(slice) => {
let range_start = self.start.as_bigint();
let range_step = self.step.as_bigint();
let _tmp_len = self.length();
let range_length = _tmp_len.as_bigint();
let range_length = &self.length();
let substep = if let Some(slice_step) = slice.step_index(vm)? {
if slice_step.is_zero() {
@@ -402,6 +397,27 @@ impl PyRange {
}
}
#[pymethod(name = "__hash__")]
fn hash(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<pyhash::PyHash> {
let length = zelf.length();
let elements = if length.is_zero() {
vec![vm.ctx.new_int(length), vm.get_none(), vm.get_none()]
} else if length.is_one() {
vec![
vm.ctx.new_int(length),
zelf.start(vm).into_object(),
vm.get_none(),
]
} else {
vec![
vm.ctx.new_int(length),
zelf.start(vm).into_object(),
zelf.step(vm).into_object(),
]
};
pyhash::hash_iter(elements.iter(), vm)
}
#[pyslot(new)]
fn tp_new(args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
let range = if args.args.len() <= 2 {