Implement array delitem by slice

This commit is contained in:
Kangzhi Shi committed 2020-09-02 11:37:27 +02:00
1 parent 2cd634f956
commit fa6b8208ec
3 files changed
+84 -4

No files matched your search

+2 -2
View File
@@ -890,7 +890,7 @@ class BaseTest:
self.assertRaises(TypeError, a.__setitem__, slice(0, 1), b)
# TODO: RUSTPYTHON
@unittest.expectedFailure
# @unittest.expectedFailure
def test_extended_set_del_slice(self):
indices = (0, None, 1, 3, 19, 100, sys.maxsize, -1, -2, -31, -100)
for start in indices:
@@ -1214,7 +1214,7 @@ class NumberTest(BaseTest):
self.assertEqual(a[-1000:-2000:-2], array.array(self.typecode, []))
# TODO: RUSTPYTHON
@unittest.expectedFailure
# @unittest.expectedFailure
def test_delslice(self):
a = array.array(self.typecode, range(5))
del a[::2]
+8
View File
@@ -34,3 +34,11 @@ a[0:0:9999999999] = c
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
a[0:0:-9999999999] = c
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
del a[::9999999999]
assert a == array(T, [1, 2, 3, 4, 5, 6, 7, 8, 100])
del a[::-9999999999]
assert a == array(T, [1, 2, 3, 4, 5, 6, 7, 8])
del a[0:0:9999999999]
assert a == array(T, [1, 2, 3, 4, 5, 6, 7, 8])
del a[0:0:-9999999999]
assert a == array(T, [1, 2, 3, 4, 5, 6, 7, 8])
+74 -2
View File
@@ -344,7 +344,79 @@ macro_rules! def_array_enum {
}
fn delitem_by_slice(&mut self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
Err(vm.new_not_implemented_error("FIX NOW".to_owned()))
let start = slice.start_index(vm)?;
let stop = slice.stop_index(vm)?;
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
if step.is_zero() {
return Err(vm.new_value_error("slice step cannot be zero".to_owned()));
}
match self {
$(ArrayContentType::$n(elements) => {
if step == BigInt::one() {
let range = get_slice_range(&start, &stop, elements.len());
if range.start < range.end {
elements.drain(range);
}
return Ok(());
}
let (start, stop, step, is_negative_step) = if step.is_negative() {
(
stop.map(|x| if x == -BigInt::one() {
elements.len() + BigInt::one()
} else {
x + 1
}),
start.map(|x| if x == -BigInt::one() {
BigInt::from(elements.len())
} else {
x + 1
}),
-step,
true
)
} else {
(start, stop, step, false)
};
let range = get_slice_range(&start, &stop, elements.len());
if range.start >= range.end {
return Ok(());
}
// step is not negative here
if let Some(step) = step.to_usize() {
let mut indexes = if is_negative_step {
itertools::Either::Left(range.clone().rev().step_by(step).rev()).peekable()
} else {
itertools::Either::Right(range.clone().step_by(step)).peekable()
};
let mut deleted = 0;
// passing whole range, swap or overlap
for i in range.clone() {
if indexes.peek() == Some(&i) {
indexes.next();
deleted += 1;
} else {
elements.swap(i - deleted, i);
}
}
// then drain (the values to delete should now be contiguous at the end of the range)
elements.drain((range.end - deleted)..range.end);
} else {
// edge case, step is too big for usize
// same behaviour as CPython
elements.remove(
if is_negative_step { range.end -1 } else { range.start }
);
}
Ok(())
})*
}
}
fn repr(&self, _vm: &VirtualMachine) -> PyResult<String> {
@@ -596,7 +668,7 @@ impl PyArray {
fn delitem(&self, needle: Either<isize, PySliceRef>, vm: &VirtualMachine) -> PyResult<()> {
match needle {
Either::A(i) => self.borrow_value_mut().delitem_by_idx(i, vm),
Either::B(slice) => self.borrow_value_mut().delitem_by_slice(slice, vm)
Either::B(slice) => self.borrow_value_mut().delitem_by_slice(slice, vm),
}
}