Skip to content

Commit fa6b820

Browse files
committed
Implement array delitem by slice
1 parent 2cd634f commit fa6b820

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

Lib/test/test_array.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ def test_setslice(self):
890890
self.assertRaises(TypeError, a.__setitem__, slice(0, 1), b)
891891

892892
# TODO: RUSTPYTHON
893-
@unittest.expectedFailure
893+
# @unittest.expectedFailure
894894
def test_extended_set_del_slice(self):
895895
indices = (0, None, 1, 3, 19, 100, sys.maxsize, -1, -2, -31, -100)
896896
for start in indices:
@@ -1214,7 +1214,7 @@ def test_extslice(self):
12141214
self.assertEqual(a[-1000:-2000:-2], array.array(self.typecode, []))
12151215

12161216
# TODO: RUSTPYTHON
1217-
@unittest.expectedFailure
1217+
# @unittest.expectedFailure
12181218
def test_delslice(self):
12191219
a = array.array(self.typecode, range(5))
12201220
del a[::2]

tests/snippets/stdlib_array.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,11 @@
3434
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
3535
a[0:0:-9999999999] = c
3636
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
37+
del a[::9999999999]
38+
assert a == array(T, [1, 2, 3, 4, 5, 6, 7, 8, 100])
39+
del a[::-9999999999]
40+
assert a == array(T, [1, 2, 3, 4, 5, 6, 7, 8])
41+
del a[0:0:9999999999]
42+
assert a == array(T, [1, 2, 3, 4, 5, 6, 7, 8])
43+
del a[0:0:-9999999999]
44+
assert a == array(T, [1, 2, 3, 4, 5, 6, 7, 8])

vm/src/stdlib/array.rs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,79 @@ macro_rules! def_array_enum {
344344
}
345345

346346
fn delitem_by_slice(&mut self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
347-
Err(vm.new_not_implemented_error("FIX NOW".to_owned()))
347+
let start = slice.start_index(vm)?;
348+
let stop = slice.stop_index(vm)?;
349+
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
350+
351+
if step.is_zero() {
352+
return Err(vm.new_value_error("slice step cannot be zero".to_owned()));
353+
}
354+
355+
match self {
356+
$(ArrayContentType::$n(elements) => {
357+
if step == BigInt::one() {
358+
let range = get_slice_range(&start, &stop, elements.len());
359+
if range.start < range.end {
360+
elements.drain(range);
361+
}
362+
return Ok(());
363+
}
364+
365+
let (start, stop, step, is_negative_step) = if step.is_negative() {
366+
(
367+
stop.map(|x| if x == -BigInt::one() {
368+
elements.len() + BigInt::one()
369+
} else {
370+
x + 1
371+
}),
372+
start.map(|x| if x == -BigInt::one() {
373+
BigInt::from(elements.len())
374+
} else {
375+
x + 1
376+
}),
377+
-step,
378+
true
379+
)
380+
} else {
381+
(start, stop, step, false)
382+
};
383+
384+
let range = get_slice_range(&start, &stop, elements.len());
385+
if range.start >= range.end {
386+
return Ok(());
387+
}
388+
389+
// step is not negative here
390+
if let Some(step) = step.to_usize() {
391+
let mut indexes = if is_negative_step {
392+
itertools::Either::Left(range.clone().rev().step_by(step).rev()).peekable()
393+
} else {
394+
itertools::Either::Right(range.clone().step_by(step)).peekable()
395+
};
396+
397+
let mut deleted = 0;
398+
399+
// passing whole range, swap or overlap
400+
for i in range.clone() {
401+
if indexes.peek() == Some(&i) {
402+
indexes.next();
403+
deleted += 1;
404+
} else {
405+
elements.swap(i - deleted, i);
406+
}
407+
}
408+
// then drain (the values to delete should now be contiguous at the end of the range)
409+
elements.drain((range.end - deleted)..range.end);
410+
} else {
411+
// edge case, step is too big for usize
412+
// same behaviour as CPython
413+
elements.remove(
414+
if is_negative_step { range.end -1 } else { range.start }
415+
);
416+
}
417+
Ok(())
418+
})*
419+
}
348420
}
349421

350422
fn repr(&self, _vm: &VirtualMachine) -> PyResult<String> {
@@ -596,7 +668,7 @@ impl PyArray {
596668
fn delitem(&self, needle: Either<isize, PySliceRef>, vm: &VirtualMachine) -> PyResult<()> {
597669
match needle {
598670
Either::A(i) => self.borrow_value_mut().delitem_by_idx(i, vm),
599-
Either::B(slice) => self.borrow_value_mut().delitem_by_slice(slice, vm)
671+
Either::B(slice) => self.borrow_value_mut().delitem_by_slice(slice, vm),
600672
}
601673
}
602674

0 commit comments

Comments
 (0)