mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Represent range with BigInts
This commit is contained in:
1
tests/snippets/builtin_range.py
Normal file
1
tests/snippets/builtin_range.py
Normal file
@@ -0,0 +1 @@
|
||||
assert range(2**63+1)[2**63] == 9223372036854775808
|
||||
@@ -9,7 +9,7 @@ use super::super::vm::VirtualMachine;
|
||||
use super::objbool;
|
||||
// use super::objstr;
|
||||
use super::objtype; // Required for arg_check! to use isinstance
|
||||
use num_bigint::ToBigInt;
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
}
|
||||
|
||||
PyObjectPayload::Range { ref range } => {
|
||||
if let Some(int) = range.get(*position as i64) {
|
||||
if let Some(int) = range.get(BigInt::from(*position)) {
|
||||
*position += 1;
|
||||
Ok(vm.ctx.new_int(int.to_bigint().unwrap()))
|
||||
} else {
|
||||
|
||||
@@ -4,27 +4,31 @@ use super::super::pyobject::{
|
||||
use super::super::vm::VirtualMachine;
|
||||
use super::objint;
|
||||
use super::objtype;
|
||||
use num_bigint::ToBigInt;
|
||||
use num_traits::ToPrimitive;
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
use num_traits::{One, Signed, ToPrimitive, Zero};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RangeType {
|
||||
// Unfortunately Rust's built in range type doesn't support things like indexing
|
||||
// or ranges where start > end so we need to roll our own.
|
||||
pub start: i64,
|
||||
pub end: i64,
|
||||
pub step: i64,
|
||||
pub start: BigInt,
|
||||
pub end: BigInt,
|
||||
pub step: BigInt,
|
||||
}
|
||||
|
||||
impl RangeType {
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
((self.end - self.start) / self.step).abs() as usize
|
||||
((self.end.clone() - self.start.clone()) / self.step.clone())
|
||||
.abs()
|
||||
.to_usize()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
(self.start <= self.end && self.step < 0) || (self.start >= self.end && self.step > 0)
|
||||
(self.start <= self.end && self.step.is_negative())
|
||||
|| (self.start >= self.end && self.step.is_positive())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -33,8 +37,8 @@ impl RangeType {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, index: i64) -> Option<i64> {
|
||||
let result = self.start + self.step * index;
|
||||
pub fn get(&self, index: BigInt) -> Option<BigInt> {
|
||||
let result = self.start.clone() + self.step.clone() * index;
|
||||
|
||||
if self.forward() && !self.is_empty() && result < self.end {
|
||||
Some(result)
|
||||
@@ -70,24 +74,24 @@ fn range_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
);
|
||||
|
||||
let start = if let Some(_) = second {
|
||||
objint::get_value(first).to_i64().unwrap()
|
||||
objint::get_value(first)
|
||||
} else {
|
||||
0i64
|
||||
BigInt::zero()
|
||||
};
|
||||
|
||||
let end = if let Some(pyint) = second {
|
||||
objint::get_value(pyint).to_i64().unwrap()
|
||||
objint::get_value(pyint)
|
||||
} else {
|
||||
objint::get_value(first).to_i64().unwrap()
|
||||
objint::get_value(first)
|
||||
};
|
||||
|
||||
let step = if let Some(pyint) = step {
|
||||
objint::get_value(pyint).to_i64().unwrap()
|
||||
objint::get_value(pyint)
|
||||
} else {
|
||||
1i64
|
||||
BigInt::one()
|
||||
};
|
||||
|
||||
if step == 0 {
|
||||
if step.is_zero() {
|
||||
Err(vm.new_value_error("range with 0 step size".to_string()))
|
||||
} else {
|
||||
Ok(PyObject::new(
|
||||
@@ -128,7 +132,7 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
args,
|
||||
required = [(zelf, Some(vm.ctx.range_type())), (subscript, None)]
|
||||
);
|
||||
let zrange = if let PyObjectPayload::Range { range } = zelf.borrow().payload {
|
||||
let zrange = if let PyObjectPayload::Range { ref range } = zelf.borrow().payload {
|
||||
range.clone()
|
||||
} else {
|
||||
unreachable!()
|
||||
@@ -136,7 +140,7 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
match subscript.borrow().payload {
|
||||
PyObjectPayload::Integer { ref value } => {
|
||||
if let Some(int) = zrange.get(value.to_i64().unwrap()) {
|
||||
if let Some(int) = zrange.get(value.clone()) {
|
||||
Ok(PyObject::new(
|
||||
PyObjectPayload::Integer {
|
||||
value: int.to_bigint().unwrap(),
|
||||
@@ -150,17 +154,17 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
PyObjectPayload::Slice { start, stop, step } => {
|
||||
let new_start = if let Some(int) = start {
|
||||
if let Some(i) = zrange.get(int.into()) {
|
||||
i as i64
|
||||
i
|
||||
} else {
|
||||
zrange.start
|
||||
zrange.start.clone()
|
||||
}
|
||||
} else {
|
||||
zrange.start
|
||||
zrange.start.clone()
|
||||
};
|
||||
|
||||
let new_end = if let Some(int) = stop {
|
||||
if let Some(i) = zrange.get(int.into()) {
|
||||
i as i64
|
||||
i
|
||||
} else {
|
||||
zrange.end
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user