mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Add bytearray.__delitem__
This commit is contained in:
@@ -187,6 +187,11 @@ impl PyByteArrayRef {
|
||||
self.inner.borrow_mut().setitem(needle, value, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__delitem__")]
|
||||
fn delitem(self, needle: Either<i32, PySliceRef>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
self.inner.borrow_mut().delitem(needle, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "isalnum")]
|
||||
fn isalnum(self, vm: &VirtualMachine) -> bool {
|
||||
self.inner.borrow().isalnum(vm)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::ops::Range;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
use num_integer::Integer;
|
||||
use num_traits::ToPrimitive;
|
||||
use num_traits::{One, Signed, ToPrimitive, Zero};
|
||||
|
||||
use super::objbytearray::{PyByteArray, PyByteArrayRef};
|
||||
use super::objbytes::{PyBytes, PyBytesRef};
|
||||
@@ -472,6 +472,140 @@ impl PyByteInner {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delitem(
|
||||
&mut self,
|
||||
needle: Either<i32, PySliceRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
match needle {
|
||||
Either::A(int) => {
|
||||
if let Some(idx) = self.elements.get_pos(int) {
|
||||
self.elements.remove(idx);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_index_error("index out of range".to_string()))
|
||||
}
|
||||
}
|
||||
Either::B(slice) => self.delslice(slice, vm),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: deduplicate this with the code in objlist
|
||||
fn delslice(&mut self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
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() {
|
||||
Err(vm.new_value_error("slice step cannot be zero".to_string()))
|
||||
} else if step.is_positive() {
|
||||
let range = self.elements.get_slice_range(&start, &stop);
|
||||
if range.start < range.end {
|
||||
#[allow(clippy::range_plus_one)]
|
||||
match step.to_i32() {
|
||||
Some(1) => {
|
||||
self._del_slice(range);
|
||||
Ok(())
|
||||
}
|
||||
Some(num) => {
|
||||
self._del_stepped_slice(range, num as usize);
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
self._del_slice(range.start..range.start + 1);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no del to do
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
// calculate the range for the reverse slice, first the bounds needs to be made
|
||||
// exclusive around stop, the lower number
|
||||
let start = start.as_ref().map(|x| {
|
||||
if *x == (-1).to_bigint().unwrap() {
|
||||
self.elements.len() + BigInt::one() //.to_bigint().unwrap()
|
||||
} else {
|
||||
x + 1
|
||||
}
|
||||
});
|
||||
let stop = stop.as_ref().map(|x| {
|
||||
if *x == (-1).to_bigint().unwrap() {
|
||||
self.elements.len().to_bigint().unwrap()
|
||||
} else {
|
||||
x + 1
|
||||
}
|
||||
});
|
||||
let range = self.elements.get_slice_range(&stop, &start);
|
||||
if range.start < range.end {
|
||||
match (-step).to_i32() {
|
||||
Some(1) => {
|
||||
self._del_slice(range);
|
||||
Ok(())
|
||||
}
|
||||
Some(num) => {
|
||||
self._del_stepped_slice_reverse(range, num as usize);
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
self._del_slice(range.end - 1..range.end);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no del to do
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _del_slice(&mut self, range: Range<usize>) {
|
||||
self.elements.drain(range);
|
||||
}
|
||||
|
||||
fn _del_stepped_slice(&mut self, range: Range<usize>, step: usize) {
|
||||
// no easy way to delete stepped indexes so here is what we'll do
|
||||
let mut deleted = 0;
|
||||
let elements = &mut self.elements;
|
||||
let mut indexes = range.clone().step_by(step).peekable();
|
||||
|
||||
for i in range.clone() {
|
||||
// is this an index to delete?
|
||||
if indexes.peek() == Some(&i) {
|
||||
// record and move on
|
||||
indexes.next();
|
||||
deleted += 1;
|
||||
} else {
|
||||
// swap towards front
|
||||
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);
|
||||
}
|
||||
|
||||
fn _del_stepped_slice_reverse(&mut self, range: Range<usize>, step: usize) {
|
||||
// no easy way to delete stepped indexes so here is what we'll do
|
||||
let mut deleted = 0;
|
||||
let elements = &mut self.elements;
|
||||
let mut indexes = range.clone().rev().step_by(step).peekable();
|
||||
|
||||
for i in range.clone().rev() {
|
||||
// is this an index to delete?
|
||||
if indexes.peek() == Some(&i) {
|
||||
// record and move on
|
||||
indexes.next();
|
||||
deleted += 1;
|
||||
} else {
|
||||
// swap towards back
|
||||
elements.swap(i + deleted, i);
|
||||
}
|
||||
}
|
||||
// then drain (the values to delete should now be contiguous at teh start of the range)
|
||||
elements.drain(range.start..(range.start + deleted));
|
||||
}
|
||||
|
||||
pub fn isalnum(&self, _vm: &VirtualMachine) -> bool {
|
||||
!self.elements.is_empty()
|
||||
&& self
|
||||
|
||||
@@ -584,23 +584,23 @@ impl PyListRef {
|
||||
}
|
||||
}
|
||||
|
||||
fn delitem(self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult {
|
||||
fn delitem(self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
|
||||
match subscript {
|
||||
SequenceIndex::Int(index) => self.delindex(index, vm),
|
||||
SequenceIndex::Slice(slice) => self.delslice(slice, vm),
|
||||
}
|
||||
}
|
||||
|
||||
fn delindex(self, index: i32, vm: &VirtualMachine) -> PyResult {
|
||||
fn delindex(self, index: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if let Some(pos_index) = self.get_pos(index) {
|
||||
self.elements.borrow_mut().remove(pos_index);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_index_error("Index out of bounds!".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn delslice(self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn delslice(self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let start = slice.start_index(vm)?;
|
||||
let stop = slice.stop_index(vm)?;
|
||||
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
|
||||
@@ -614,20 +614,20 @@ impl PyListRef {
|
||||
match step.to_i32() {
|
||||
Some(1) => {
|
||||
self._del_slice(range);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
Some(num) => {
|
||||
self._del_stepped_slice(range, num as usize);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
self._del_slice(range.start..range.start + 1);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no del to do
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
// calculate the range for the reverse slice, first the bounds needs to be made
|
||||
@@ -651,20 +651,20 @@ impl PyListRef {
|
||||
match (-step).to_i32() {
|
||||
Some(1) => {
|
||||
self._del_slice(range);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
Some(num) => {
|
||||
self._del_stepped_slice_reverse(range, num as usize);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
self._del_slice(range.end - 1..range.end);
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no del to do
|
||||
Ok(vm.get_none())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user