Skip to content

Commit 9ac8e55

Browse files
committed
Represent range with BigInts
1 parent f4a78d4 commit 9ac8e55

File tree

3 files changed

+30
-25
lines changed

3 files changed

+30
-25
lines changed

tests/snippets/builtin_range.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
assert range(2**63+1)[2**63] == 9223372036854775808

vm/src/obj/objiter.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use super::super::vm::VirtualMachine;
99
use super::objbool;
1010
// use super::objstr;
1111
use super::objtype; // Required for arg_check! to use isinstance
12-
use num_bigint::ToBigInt;
12+
use num_bigint::{BigInt, ToBigInt};
1313

1414
/*
1515
* This helper function is called at multiple places. First, it is called
@@ -121,7 +121,7 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
121121
}
122122

123123
PyObjectPayload::Range { ref range } => {
124-
if let Some(int) = range.get(*position as i64) {
124+
if let Some(int) = range.get(BigInt::from(*position)) {
125125
*position += 1;
126126
Ok(vm.ctx.new_int(int.to_bigint().unwrap()))
127127
} else {

vm/src/obj/objrange.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,31 @@ use super::super::pyobject::{
44
use super::super::vm::VirtualMachine;
55
use super::objint;
66
use super::objtype;
7-
use num_bigint::ToBigInt;
8-
use num_traits::ToPrimitive;
7+
use num_bigint::{BigInt, ToBigInt};
8+
use num_traits::{One, Signed, ToPrimitive, Zero};
99

10-
#[derive(Debug, Copy, Clone)]
10+
#[derive(Debug, Clone)]
1111
pub struct RangeType {
1212
// Unfortunately Rust's built in range type doesn't support things like indexing
1313
// or ranges where start > end so we need to roll our own.
14-
pub start: i64,
15-
pub end: i64,
16-
pub step: i64,
14+
pub start: BigInt,
15+
pub end: BigInt,
16+
pub step: BigInt,
1717
}
1818

1919
impl RangeType {
2020
#[inline]
2121
pub fn len(&self) -> usize {
22-
((self.end - self.start) / self.step).abs() as usize
22+
((self.end.clone() - self.start.clone()) / self.step.clone())
23+
.abs()
24+
.to_usize()
25+
.unwrap()
2326
}
2427

2528
#[inline]
2629
pub fn is_empty(&self) -> bool {
27-
(self.start <= self.end && self.step < 0) || (self.start >= self.end && self.step > 0)
30+
(self.start <= self.end && self.step.is_negative())
31+
|| (self.start >= self.end && self.step.is_positive())
2832
}
2933

3034
#[inline]
@@ -33,8 +37,8 @@ impl RangeType {
3337
}
3438

3539
#[inline]
36-
pub fn get(&self, index: i64) -> Option<i64> {
37-
let result = self.start + self.step * index;
40+
pub fn get(&self, index: BigInt) -> Option<BigInt> {
41+
let result = self.start.clone() + self.step.clone() * index;
3842

3943
if self.forward() && !self.is_empty() && result < self.end {
4044
Some(result)
@@ -70,24 +74,24 @@ fn range_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7074
);
7175

7276
let start = if let Some(_) = second {
73-
objint::get_value(first).to_i64().unwrap()
77+
objint::get_value(first)
7478
} else {
75-
0i64
79+
BigInt::zero()
7680
};
7781

7882
let end = if let Some(pyint) = second {
79-
objint::get_value(pyint).to_i64().unwrap()
83+
objint::get_value(pyint)
8084
} else {
81-
objint::get_value(first).to_i64().unwrap()
85+
objint::get_value(first)
8286
};
8387

8488
let step = if let Some(pyint) = step {
85-
objint::get_value(pyint).to_i64().unwrap()
89+
objint::get_value(pyint)
8690
} else {
87-
1i64
91+
BigInt::one()
8892
};
8993

90-
if step == 0 {
94+
if step.is_zero() {
9195
Err(vm.new_value_error("range with 0 step size".to_string()))
9296
} else {
9397
Ok(PyObject::new(
@@ -128,15 +132,15 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
128132
args,
129133
required = [(zelf, Some(vm.ctx.range_type())), (subscript, None)]
130134
);
131-
let zrange = if let PyObjectPayload::Range { range } = zelf.borrow().payload {
135+
let zrange = if let PyObjectPayload::Range { ref range } = zelf.borrow().payload {
132136
range.clone()
133137
} else {
134138
unreachable!()
135139
};
136140

137141
match subscript.borrow().payload {
138142
PyObjectPayload::Integer { ref value } => {
139-
if let Some(int) = zrange.get(value.to_i64().unwrap()) {
143+
if let Some(int) = zrange.get(value.clone()) {
140144
Ok(PyObject::new(
141145
PyObjectPayload::Integer {
142146
value: int.to_bigint().unwrap(),
@@ -150,17 +154,17 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
150154
PyObjectPayload::Slice { start, stop, step } => {
151155
let new_start = if let Some(int) = start {
152156
if let Some(i) = zrange.get(int.into()) {
153-
i as i64
157+
i
154158
} else {
155-
zrange.start
159+
zrange.start.clone()
156160
}
157161
} else {
158-
zrange.start
162+
zrange.start.clone()
159163
};
160164

161165
let new_end = if let Some(int) = stop {
162166
if let Some(i) = zrange.get(int.into()) {
163-
i as i64
167+
i
164168
} else {
165169
zrange.end
166170
}

0 commit comments

Comments
 (0)