Skip to content

Commit 8c411bc

Browse files
authored
Merge pull request RustPython#1381 from HyeockJinKim/range
Fixed calculation for range
2 parents 3dfb04e + c141e6d commit 8c411bc

File tree

2 files changed

+75
-24
lines changed

2 files changed

+75
-24
lines changed

tests/snippets/builtin_range.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@
1919
assert_raises(ValueError, lambda: range(10).index('foo'), 'not an int')
2020
assert_raises(ValueError, lambda: range(1, 10, 0), 'step is zero')
2121

22+
# get tests
23+
assert range(10)[0] == 0
24+
assert range(10)[9] == 9
25+
assert range(10, 0, -1)[0] == 10
26+
assert range(10, 0, -1)[9] == 1
27+
assert_raises(IndexError, lambda: range(10)[10], 'out of bound')
28+
29+
# slice tests
30+
assert range(10)[0:3] == range(3)
31+
assert range(10)[-5:9] == range(5, 9)
32+
assert range(10)[100:10] == range(10, 10)
33+
assert range(10)[-15:3] == range(0, 3)
34+
assert range(10, 100, 3)[4:1000:5] == range(22, 100, 15)
35+
assert range(10)[:] == range(10)
36+
assert range(10, 0, -2)[0:5:2] == range(10, 0, -4)
37+
assert range(10)[10:11] == range(10,10)
38+
2239
# count tests
2340
assert range(10).count(2) == 1
2441
assert range(10).count(11) == 0
@@ -86,3 +103,5 @@
86103
assert_raises(IndexError, lambda: range(10)[-11], 'out of bound')
87104
assert range(10)[-2:4] == range(8, 4)
88105
assert range(10)[-6:-2] == range(4, 8)
106+
assert range(50, 0, -2)[-5] == 10
107+
assert range(50, 0, -2)[-5:3:5] == range(10, 44, -10)

vm/src/obj/objrange.rs

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -77,26 +77,32 @@ impl PyRange {
7777
let start = self.start.as_bigint();
7878
let stop = self.stop.as_bigint();
7979
let step = self.step.as_bigint();
80+
let index = index.clone();
81+
if self.is_empty() {
82+
return None;
83+
}
84+
85+
let length = if start < stop {
86+
(stop - start - 1) / step + 1
87+
} else {
88+
(start - stop - 1) / (-step) + 1
89+
};
8090

81-
let index = if *index < BigInt::zero() {
82-
let index = stop + index;
83-
if index < BigInt::zero() {
91+
let index = if index < BigInt::zero() {
92+
let new_index = &length + &index;
93+
if new_index < BigInt::zero() {
8494
return None;
8595
}
86-
index
96+
length + index
8797
} else {
88-
index.clone()
98+
if length <= index {
99+
return None;
100+
}
101+
index
89102
};
90103

91-
let result = start + step * &index;
92-
93-
if (self.forward() && !self.is_empty() && result < *stop)
94-
|| (!self.forward() && !self.is_empty() && result > *stop)
95-
{
96-
Some(result)
97-
} else {
98-
None
99-
}
104+
let result = start + step * index;
105+
Some(result)
100106
}
101107
}
102108

@@ -293,17 +299,23 @@ impl PyRange {
293299
#[pymethod(name = "__getitem__")]
294300
fn getitem(&self, subscript: RangeIndex, vm: &VirtualMachine) -> PyResult {
295301
match subscript {
296-
RangeIndex::Int(index) => {
297-
if let Some(value) = self.get(index.as_bigint()) {
298-
Ok(PyInt::new(value).into_ref(vm).into_object())
299-
} else {
300-
Err(vm.new_index_error("range object index out of range".to_string()))
301-
}
302-
}
303302
RangeIndex::Slice(slice) => {
303+
let start = self.start.as_bigint();
304+
let stop = self.stop.as_bigint();
305+
let step = self.step.as_bigint();
306+
304307
let new_start = if let Some(int) = slice.start_index(vm)? {
305-
if let Some(i) = self.get(&int) {
308+
let int = &int;
309+
if let Some(i) = self.get(int) {
306310
PyInt::new(i).into_ref(vm)
311+
} else if start < stop {
312+
if stop <= int {
313+
self.stop.clone()
314+
} else {
315+
self.start.clone()
316+
}
317+
} else if int < stop {
318+
self.stop.clone()
307319
} else {
308320
self.start.clone()
309321
}
@@ -312,8 +324,17 @@ impl PyRange {
312324
};
313325

314326
let new_end = if let Some(int) = slice.stop_index(vm)? {
315-
if let Some(i) = self.get(&int) {
327+
let int = &int;
328+
if let Some(i) = self.get(int) {
316329
PyInt::new(i).into_ref(vm)
330+
} else if start < stop {
331+
if int < start {
332+
self.start.clone()
333+
} else {
334+
self.stop.clone()
335+
}
336+
} else if start < int {
337+
self.start.clone()
317338
} else {
318339
self.stop.clone()
319340
}
@@ -322,7 +343,11 @@ impl PyRange {
322343
};
323344

324345
let new_step = if let Some(int) = slice.step_index(vm)? {
325-
PyInt::new(int * self.step.as_bigint()).into_ref(vm)
346+
if step.is_zero() {
347+
return Err(vm.new_value_error("slice step cannot be zero".to_string()));
348+
} else {
349+
PyInt::new(int * self.step.as_bigint()).into_ref(vm)
350+
}
326351
} else {
327352
self.step.clone()
328353
};
@@ -335,6 +360,13 @@ impl PyRange {
335360
.into_ref(vm)
336361
.into_object())
337362
}
363+
RangeIndex::Int(index) => {
364+
if let Some(value) = self.get(index.as_bigint()) {
365+
Ok(PyInt::new(value).into_ref(vm).into_object())
366+
} else {
367+
Err(vm.new_index_error("range object index out of range".to_string()))
368+
}
369+
}
338370
}
339371
}
340372

0 commit comments

Comments
 (0)