Skip to content

Commit a262791

Browse files
Merge pull request RustPython#353 from OddCoincidence/range-index
Add range.index
2 parents f13cb62 + 49a23a8 commit a262791

File tree

5 files changed

+69
-0
lines changed

5 files changed

+69
-0
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/snippets/builtin_range.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,31 @@
1+
def assert_raises(expr, exc_type):
2+
"""
3+
Helper function to assert `expr` raises an exception of type `exc_type`
4+
Args:
5+
expr: Callable
6+
exec_type: Exception
7+
Returns:
8+
None
9+
Raises:
10+
Assertion error on failure
11+
"""
12+
try:
13+
expr(None)
14+
except exc_type:
15+
assert True
16+
else:
17+
assert False
18+
119
assert range(2**63+1)[2**63] == 9223372036854775808
20+
21+
# index tests
22+
assert range(10).index(6) == 6
23+
assert range(4, 10).index(6) == 2
24+
assert range(4, 10, 2).index(6) == 1
25+
26+
# index raises value error on out of bounds
27+
assert_raises(lambda _: range(10).index(-1), ValueError)
28+
assert_raises(lambda _: range(10).index(10), ValueError)
29+
30+
# index raises value error if out of step
31+
assert_raises(lambda _: range(4, 10, 2).index(5), ValueError)

vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ bitflags = "1.0.4"
88
num-complex = "0.2"
99
num-bigint = "0.2.1"
1010
num-traits = "0.2"
11+
num-integer = "0.1.39"
1112
rand = "0.5"
1213
log = "0.3"
1314
rustpython_parser = {path = "../parser"}

vm/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern crate log;
1212
// extern crate env_logger;
1313
extern crate num_bigint;
1414
extern crate num_complex;
15+
extern crate num_integer;
1516
extern crate num_traits;
1617
extern crate serde;
1718
extern crate serde_json;

vm/src/obj/objrange.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::super::vm::VirtualMachine;
55
use super::objint;
66
use super::objtype;
77
use num_bigint::{BigInt, ToBigInt};
8+
use num_integer::Integer;
89
use num_traits::{One, Signed, ToPrimitive, Zero};
910

1011
#[derive(Debug, Clone)]
@@ -25,6 +26,20 @@ impl RangeType {
2526
.unwrap()
2627
}
2728

29+
#[inline]
30+
pub fn index_of(&self, value: &BigInt) -> Option<BigInt> {
31+
if value < &self.start || value >= &self.end {
32+
return None;
33+
}
34+
35+
let offset = value - &self.start;
36+
if offset.is_multiple_of(&self.step) {
37+
Some(offset / &self.step)
38+
} else {
39+
None
40+
}
41+
}
42+
2843
#[inline]
2944
pub fn is_empty(&self) -> bool {
3045
(self.start <= self.end && self.step.is_negative())
@@ -60,6 +75,7 @@ pub fn init(context: &PyContext) {
6075
"__getitem__",
6176
context.new_rustfunc(range_getitem),
6277
);
78+
context.set_attr(&range_type, "index", context.new_rustfunc(range_index));
6379
}
6480

6581
fn range_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -193,3 +209,23 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
193209
_ => Err(vm.new_type_error("range indices must be integer or slice".to_string())),
194210
}
195211
}
212+
213+
fn range_index(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
214+
arg_check!(
215+
vm,
216+
args,
217+
required = [(zelf, Some(vm.ctx.range_type())), (needle, None)]
218+
);
219+
220+
if let PyObjectPayload::Range { ref range } = zelf.borrow().payload {
221+
match needle.borrow().payload {
222+
PyObjectPayload::Integer { ref value } => match range.index_of(value) {
223+
Some(idx) => Ok(vm.ctx.new_int(idx)),
224+
None => Err(vm.new_value_error(format!("{} is not in range", value))),
225+
},
226+
_ => Err(vm.new_value_error("sequence.index(x): x not in sequence".to_string())),
227+
}
228+
} else {
229+
unreachable!()
230+
}
231+
}

0 commit comments

Comments
 (0)