Merge pull request #1897 from youknowone/fix-bytes-find

Fix find/index/count not to crash for bigint start/end arguments
This commit is contained in:
Jeong YunWon authored and GitHub committed 2020-05-01 00:51:23 +09:00
commit 46945c334c
5 files changed
+57 -67

No files matched your search

-4
View File
@@ -156,8 +156,6 @@ class BaseTest:
self.assertEqual(rem, 0, '%s != 0 for %s' % (rem, i))
self.assertEqual(r1, r2, '%s != %s for %s' % (r1, r2, i))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_find(self):
self.checkequal(0, 'abcdefghiabc', 'find', 'abc')
self.checkequal(9, 'abcdefghiabc', 'find', 'abc', 1)
@@ -215,8 +213,6 @@ class BaseTest:
if loc != -1:
self.assertEqual(i[loc:loc+len(j)], j)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_rfind(self):
self.checkequal(9, 'abcdefghiabc', 'rfind', 'abc')
self.checkequal(12, 'abcdefghiabc', 'rfind', '')
+2 -4
View File
@@ -199,8 +199,7 @@ class UnicodeTest(string_tests.CommonTest,
self.checkequal(0, 'a' * 10, 'count', 'a\U00100304')
self.checkequal(0, '\u0102' * 10, 'count', '\u0102\U00100304')
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.skip("TODO: RUSTPYTHON")
def test_find(self):
string_tests.CommonTest.test_find(self)
# test implementation details of the memchr fast path
@@ -232,8 +231,7 @@ class UnicodeTest(string_tests.CommonTest,
self.checkequal(-1, 'a' * 100, 'find', 'a\U00100304')
self.checkequal(-1, '\u0102' * 100, 'find', '\u0102\U00100304')
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.skip("TODO: RUSTPYTHON")
def test_rfind(self):
string_tests.CommonTest.test_rfind(self)
# test implementation details of the memrchr fast path
+4 -4
View File
@@ -154,10 +154,10 @@ impl ByteInnerNewOptions {
pub struct ByteInnerFindOptions {
#[pyarg(positional_only, optional = false)]
sub: Either<PyByteInner, PyIntRef>,
#[pyarg(positional_only, optional = true)]
start: OptionalArg<Option<isize>>,
#[pyarg(positional_only, optional = true)]
end: OptionalArg<Option<isize>>,
#[pyarg(positional_only, default = "None")]
start: Option<PyIntRef>,
#[pyarg(positional_only, default = "None")]
end: Option<PyIntRef>,
}
impl ByteInnerFindOptions {
+30 -46
View File
@@ -816,63 +816,35 @@ impl PyString {
}
#[inline]
fn _find<F>(
&self,
sub: PyStringRef,
start: OptionalArg<Option<isize>>,
end: OptionalArg<Option<isize>>,
find: F,
) -> Option<usize>
fn _find<F>(&self, args: FindArgs, find: F) -> Option<usize>
where
F: Fn(&str, &str) -> Option<usize>,
{
let range = adjust_indices(start, end, self.value.len());
let (sub, range) = args.get_value(self.len());
self.value.py_find(&sub.value, range, find)
}
#[pymethod]
fn find(
&self,
sub: PyStringRef,
start: OptionalArg<Option<isize>>,
end: OptionalArg<Option<isize>>,
) -> isize {
self._find(sub, start, end, |r, s| r.find(s))
fn find(&self, args: FindArgs) -> isize {
self._find(args, |r, s| r.find(s))
.map_or(-1, |v| v as isize)
}
#[pymethod]
fn rfind(
&self,
sub: PyStringRef,
start: OptionalArg<Option<isize>>,
end: OptionalArg<Option<isize>>,
) -> isize {
self._find(sub, start, end, |r, s| r.rfind(s))
fn rfind(&self, args: FindArgs) -> isize {
self._find(args, |r, s| r.rfind(s))
.map_or(-1, |v| v as isize)
}
#[pymethod]
fn index(
&self,
sub: PyStringRef,
start: OptionalArg<Option<isize>>,
end: OptionalArg<Option<isize>>,
vm: &VirtualMachine,
) -> PyResult<usize> {
self._find(sub, start, end, |r, s| r.find(s))
fn index(&self, args: FindArgs, vm: &VirtualMachine) -> PyResult<usize> {
self._find(args, |r, s| r.find(s))
.ok_or_else(|| vm.new_value_error("substring not found".to_owned()))
}
#[pymethod]
fn rindex(
&self,
sub: PyStringRef,
start: OptionalArg<Option<isize>>,
end: OptionalArg<Option<isize>>,
vm: &VirtualMachine,
) -> PyResult<usize> {
self._find(sub, start, end, |r, s| r.rfind(s))
fn rindex(&self, args: FindArgs, vm: &VirtualMachine) -> PyResult<usize> {
self._find(args, |r, s| r.rfind(s))
.ok_or_else(|| vm.new_value_error("substring not found".to_owned()))
}
@@ -947,15 +919,10 @@ impl PyString {
}
#[pymethod]
fn count(
&self,
sub: PyStringRef,
start: OptionalArg<Option<isize>>,
end: OptionalArg<Option<isize>>,
) -> usize {
let range = adjust_indices(start, end, self.value.len());
fn count(&self, args: FindArgs) -> usize {
let (needle, range) = args.get_value(self.len());
self.value
.py_count(&sub.value, range, |h, n| h.matches(n).count())
.py_count(&needle.value, range, |h, n| h.matches(n).count())
}
#[pymethod]
@@ -1256,6 +1223,23 @@ impl TryFromObject for std::ffi::CString {
type SplitArgs = pystr::SplitArgs<PyStringRef, str, char>;
#[derive(FromArgs)]
pub struct FindArgs {
#[pyarg(positional_only, optional = false)]
sub: PyStringRef,
#[pyarg(positional_only, default = "None")]
start: Option<PyIntRef>,
#[pyarg(positional_only, default = "None")]
end: Option<PyIntRef>,
}
impl FindArgs {
fn get_value(self, len: usize) -> (PyStringRef, std::ops::Range<usize>) {
let range = adjust_indices(self.start, self.end, len);
(self.sub, range)
}
}
pub fn init(ctx: &PyContext) {
PyString::extend_class(ctx, &ctx.types.str_type);
+21 -9
View File
@@ -1,7 +1,8 @@
use crate::function::{single_or_tuple_any, OptionalOption};
use crate::obj::objint::PyIntRef;
use crate::pyobject::{PyObjectRef, PyResult, TryFromObject, TypeProtocol};
use crate::vm::VirtualMachine;
use num_traits::cast::ToPrimitive;
use num_traits::{cast::ToPrimitive, sign::Signed};
#[derive(FromArgs)]
pub struct SplitArgs<T, S, E>
@@ -58,10 +59,10 @@ impl ExpandTabsArgs {
pub struct StartsEndsWithArgs {
#[pyarg(positional_only, optional = false)]
affix: PyObjectRef,
#[pyarg(positional_only, optional = true)]
start: OptionalOption<isize>,
#[pyarg(positional_only, optional = true)]
end: OptionalOption<isize>,
#[pyarg(positional_only, default = "None")]
start: Option<PyIntRef>,
#[pyarg(positional_only, default = "None")]
end: Option<PyIntRef>,
}
impl StartsEndsWithArgs {
@@ -71,14 +72,25 @@ impl StartsEndsWithArgs {
}
}
fn cap_to_isize(py_int: PyIntRef) -> isize {
let big = py_int.as_bigint();
big.to_isize().unwrap_or_else(|| {
if big.is_negative() {
std::isize::MIN
} else {
std::isize::MAX
}
})
}
// help get optional string indices
pub fn adjust_indices(
start: OptionalOption<isize>,
end: OptionalOption<isize>,
start: Option<PyIntRef>,
end: Option<PyIntRef>,
len: usize,
) -> std::ops::Range<usize> {
let mut start = start.flat_option().unwrap_or(0);
let mut end = end.flat_option().unwrap_or(len as isize);
let mut start = start.map_or(0, cap_to_isize);
let mut end = end.map_or(len as isize, cap_to_isize);
if end > len as isize {
end = len as isize;
} else if end < 0 {