mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Add Rust accelerator module for bisect.
This commit is contained in:
1 parent
658d175e5b
commit
95ce95c9f0
4 files changed
+169
-18
No files matched your search
Vendored
+4
-5
@@ -19,8 +19,6 @@ def insort_right(a, x, lo=0, hi=None):
|
||||
else: lo = mid+1
|
||||
a.insert(lo, x)
|
||||
|
||||
insort = insort_right # backward compatibility
|
||||
|
||||
def bisect_right(a, x, lo=0, hi=None):
|
||||
"""Return the index where to insert item x in list a, assuming a is sorted.
|
||||
|
||||
@@ -42,8 +40,6 @@ def bisect_right(a, x, lo=0, hi=None):
|
||||
else: lo = mid+1
|
||||
return lo
|
||||
|
||||
bisect = bisect_right # backward compatibility
|
||||
|
||||
def insort_left(a, x, lo=0, hi=None):
|
||||
"""Insert item x in list a, and keep it sorted assuming a is sorted.
|
||||
|
||||
@@ -85,8 +81,11 @@ def bisect_left(a, x, lo=0, hi=None):
|
||||
else: hi = mid
|
||||
return lo
|
||||
|
||||
# Overwrite above definitions with a fast C implementation
|
||||
# Overwrite above definitions with a fast Rust implementation
|
||||
try:
|
||||
from _bisect import *
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
bisect = bisect_right # backward compatibility
|
||||
insort = insort_right # backward compatibility
|
||||
+9
-13
@@ -4,7 +4,7 @@ from test import support
|
||||
from collections import UserList
|
||||
|
||||
py_bisect = support.import_fresh_module('bisect', blocked=['_bisect'])
|
||||
c_bisect = None
|
||||
rust_bisect = support.import_fresh_module('bisect', fresh=['bisect'])
|
||||
|
||||
class Range(object):
|
||||
"""A trivial range()-like object that has an insert() method."""
|
||||
@@ -202,9 +202,8 @@ class TestBisect:
|
||||
class TestBisectPython(TestBisect, unittest.TestCase):
|
||||
module = py_bisect
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON, _bisect module")
|
||||
class TestBisectC(TestBisect, unittest.TestCase):
|
||||
module = c_bisect
|
||||
class TestBisectRust(TestBisect, unittest.TestCase):
|
||||
module = rust_bisect
|
||||
|
||||
#==============================================================================
|
||||
|
||||
@@ -238,9 +237,8 @@ class TestInsort:
|
||||
class TestInsortPython(TestInsort, unittest.TestCase):
|
||||
module = py_bisect
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON, _bisect module")
|
||||
class TestInsortC(TestInsort, unittest.TestCase):
|
||||
module = c_bisect
|
||||
class TestInsortRust(TestInsort, unittest.TestCase):
|
||||
module = rust_bisect
|
||||
|
||||
#==============================================================================
|
||||
|
||||
@@ -294,9 +292,8 @@ class TestErrorHandling:
|
||||
class TestErrorHandlingPython(TestErrorHandling, unittest.TestCase):
|
||||
module = py_bisect
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON, _bisect module")
|
||||
class TestErrorHandlingC(TestErrorHandling, unittest.TestCase):
|
||||
module = c_bisect
|
||||
class TestErrorHandlingRust(TestErrorHandling, unittest.TestCase):
|
||||
module = rust_bisect
|
||||
|
||||
#==============================================================================
|
||||
|
||||
@@ -322,9 +319,8 @@ class TestDocExample:
|
||||
class TestDocExamplePython(TestDocExample, unittest.TestCase):
|
||||
module = py_bisect
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON, _bisect module")
|
||||
class TestDocExampleC(TestDocExample, unittest.TestCase):
|
||||
module = c_bisect
|
||||
class TestDocExampleRust(TestDocExample, unittest.TestCase):
|
||||
module = rust_bisect
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
pub(crate) use _bisect::make_module;
|
||||
|
||||
#[pymodule]
|
||||
mod _bisect {
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::function::OptionalArg;
|
||||
use crate::slots::PyComparisonOp::Lt;
|
||||
use crate::vm::VirtualMachine;
|
||||
use crate::{ItemProtocol, PyObjectRef, PyResult};
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct BisectArgs {
|
||||
#[pyarg(any, name = "a")]
|
||||
a: PyObjectRef,
|
||||
#[pyarg(any, name = "x")]
|
||||
x: PyObjectRef,
|
||||
#[pyarg(any, optional, name = "lo")]
|
||||
lo: OptionalArg<PyObjectRef>,
|
||||
#[pyarg(any, optional, name = "hi")]
|
||||
hi: OptionalArg<PyObjectRef>,
|
||||
}
|
||||
|
||||
// Handles objects that implement __index__ and makes sure index fits in needed isize.
|
||||
#[inline]
|
||||
fn handle_default(
|
||||
arg: OptionalArg<PyObjectRef>,
|
||||
default: Option<isize>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<isize>> {
|
||||
Ok(match arg {
|
||||
OptionalArg::Present(v) => {
|
||||
Some(vm.to_index(&v)?.as_bigint().to_isize().ok_or_else(|| {
|
||||
vm.new_index_error("cannot fit 'int' into an index-sized integer".to_owned())
|
||||
})?)
|
||||
}
|
||||
OptionalArg::Missing => default,
|
||||
})
|
||||
}
|
||||
|
||||
// Handles defaults for lo, hi.
|
||||
//
|
||||
// - lo must be >= 0 with a default of 0.
|
||||
// - hi, while it could be negative, defaults to `0` and the same effect is achieved
|
||||
// (while loop isn't entered); this way we keep it a usize (and, if my understanding
|
||||
// is correct, issue 13496 is handled). Its default value is set to the length of the
|
||||
// input sequence.
|
||||
#[inline]
|
||||
fn as_usize(
|
||||
lo: OptionalArg<PyObjectRef>,
|
||||
hi: OptionalArg<PyObjectRef>,
|
||||
seq_len: usize,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<(usize, usize)> {
|
||||
// We only deal with positives for lo, try_from can't fail.
|
||||
// Default is always a Some so we can safely unwrap.
|
||||
let lo = handle_default(lo, Some(0), vm)?
|
||||
.map(|value| {
|
||||
if value < 0 {
|
||||
return Err(vm.new_value_error("lo must be non-negative".to_owned()));
|
||||
}
|
||||
Ok(usize::try_from(value).unwrap())
|
||||
})
|
||||
.unwrap()?;
|
||||
let hi = handle_default(hi, None, vm)?
|
||||
.map(|value| {
|
||||
if value < 0 {
|
||||
0
|
||||
} else {
|
||||
// Can't fail.
|
||||
usize::try_from(value).unwrap()
|
||||
}
|
||||
})
|
||||
.unwrap_or(seq_len);
|
||||
Ok((lo, hi))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bisect_left_impl(
|
||||
BisectArgs { a, x, lo, hi }: BisectArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<usize> {
|
||||
let (mut lo, mut hi) = as_usize(lo, hi, vm.obj_len(&a)?, vm)?;
|
||||
|
||||
while lo < hi {
|
||||
// Handles issue 13496.
|
||||
let mid = (lo + hi) / 2;
|
||||
if vm.bool_cmp(&a.get_item(mid, vm)?, &x, Lt)? {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
Ok(lo)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bisect_right_impl(
|
||||
BisectArgs { a, x, lo, hi }: BisectArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<usize> {
|
||||
let (mut lo, mut hi) = as_usize(lo, hi, vm.obj_len(&a)?, vm)?;
|
||||
|
||||
while lo < hi {
|
||||
// Handles issue 13496.
|
||||
let mid = (lo + hi) / 2;
|
||||
if vm.bool_cmp(&x, &a.get_item(mid, vm)?, Lt)? {
|
||||
hi = mid;
|
||||
} else {
|
||||
lo = mid + 1;
|
||||
}
|
||||
}
|
||||
Ok(lo)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn bisect_left(args: BisectArgs, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
bisect_left_impl(args, vm)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn bisect_right(args: BisectArgs, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
bisect_right_impl(args, vm)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn insort_left(BisectArgs { a, x, lo, hi }: BisectArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let index = bisect_left_impl(
|
||||
BisectArgs {
|
||||
a: a.clone(),
|
||||
x: x.clone(),
|
||||
lo,
|
||||
hi,
|
||||
},
|
||||
vm,
|
||||
)?;
|
||||
vm.call_method(&a, "insert", (index, x))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn insort_right(BisectArgs { a, x, lo, hi }: BisectArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let index = bisect_right_impl(
|
||||
BisectArgs {
|
||||
a: a.clone(),
|
||||
x: x.clone(),
|
||||
lo,
|
||||
hi,
|
||||
},
|
||||
vm,
|
||||
)?;
|
||||
vm.call_method(&a, "insert", (index, x))
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ pub mod array;
|
||||
pub(crate) mod ast;
|
||||
mod atexit;
|
||||
mod binascii;
|
||||
mod bisect;
|
||||
mod codecs;
|
||||
mod collections;
|
||||
mod csv;
|
||||
@@ -104,6 +105,7 @@ pub fn get_module_inits() -> StdlibMap {
|
||||
"array" => array::make_module,
|
||||
"atexit" => atexit::make_module,
|
||||
"binascii" => binascii::make_module,
|
||||
"_bisect" => bisect::make_module,
|
||||
"_codecs" => codecs::make_module,
|
||||
"_collections" => collections::make_module,
|
||||
"_csv" => csv::make_module,
|
||||
|
||||
Reference in new issue
Block a user