Fix: array with float type should accept integer parameter

This commit is contained in:
Kangzhi Shi committed 2020-08-31 11:48:50 +02:00
1 parent 92d8e2c8da
commit 1150f507e2
2 files changed
+75 -19

No files matched your search

+13 -1
View File
@@ -19,4 +19,16 @@ a = array("b", [0, 1, 2, 3])
b = a
assert a.__ne__(b) is False
b = array("B", [3, 2, 1, 0])
assert a.__ne__(b) is True
assert a.__ne__(b) is True
def test_float_with_integer_input():
f = array("f", [0, 1, 2.0, 3.0])
f.append(4)
f.insert(0, -1)
assert f.count(4) == 1
f.remove(1)
assert f.index(0) == 1
f[0] = -2
assert f == array("f", [-2, 0, 2, 3, 4])
test_float_with_integer_input()
+62 -18
View File
@@ -4,6 +4,7 @@ use crate::common::cell::{
};
use crate::function::OptionalArg;
use crate::obj::objbytes::PyBytesRef;
use crate::obj::objfloat::try_float;
use crate::obj::objsequence::PySliceableSequence;
use crate::obj::objslice::PySliceRef;
use crate::obj::objstr::PyStringRef;
@@ -11,7 +12,7 @@ use crate::obj::objtype::PyClassRef;
use crate::obj::{objbool, objiter};
use crate::pyobject::{
BorrowValue, Either, IntoPyObject, PyArithmaticValue, PyClassImpl, PyComparisonValue,
PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
};
use crate::VirtualMachine;
use crossbeam_utils::atomic::AtomicCell;
@@ -74,7 +75,7 @@ macro_rules! def_array_enum {
fn push(&mut self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
match self {
$(ArrayContentType::$n(v) => {
let val = $t::try_from_object(vm, obj)?;
let val = $t::try_into_from_object(vm, obj)?;
v.push(val);
})*
}
@@ -92,7 +93,7 @@ macro_rules! def_array_enum {
fn insert(&mut self, i: usize, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
match self {
$(ArrayContentType::$n(v) => {
let val = $t::try_from_object(vm, obj)?;
let val = $t::try_into_from_object(vm, obj)?;
v.insert(i, val);
})*
}
@@ -102,9 +103,11 @@ macro_rules! def_array_enum {
fn count(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
match self {
$(ArrayContentType::$n(v) => {
Ok(<Option<$t>>::try_from_object(vm, obj)?.map_or(0, |val| {
Ok(if let Ok(val) = $t::try_into_from_object(vm, obj) {
v.iter().filter(|&&a| a == val).count()
}))
} else {
0
})
})*
}
}
@@ -112,13 +115,15 @@ macro_rules! def_array_enum {
fn remove(&mut self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()>{
match self {
$(ArrayContentType::$n(v) => {
let pos = <Option<$t>>::try_from_object(vm, obj)?.map_or(None, |val| {
v.iter().position(|&a| a == val)
}).ok_or_else(||vm.new_value_error("array.remove(x): x not in array".to_owned()) )?;
v.remove(pos);
if let Ok(val) = $t::try_into_from_object(vm, obj) {
if let Some(pos) = v.iter().position(|&a| a == val) {
v.remove(pos);
return Ok(());
}
}
Err(vm.new_value_error("array.remove(x): x not in array".to_owned()))
})*
}
Ok(())
}
fn frombytes(&mut self, b: &[u8]) {
@@ -156,12 +161,15 @@ macro_rules! def_array_enum {
}
}
fn index(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<usize>> {
fn index(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
match self {
$(ArrayContentType::$n(v) => {
Ok(<Option<$t>>::try_from_object(vm, x)?.map_or(None, |val| {
v.iter().position(|&a| a == val)
}))
if let Ok(val) = $t::try_into_from_object(vm, obj) {
if let Some(pos) = v.iter().position(|&a| a == val) {
return Ok(pos);
}
}
Err(vm.new_value_error("array.index(x): x not in array".to_owned()))
})*
}
}
@@ -228,7 +236,7 @@ macro_rules! def_array_enum {
Either::A(i) => {
let i = self.idx(i, "array assignment", vm)?;
match self {
$(ArrayContentType::$n(v) => { v[i] = TryFromObject::try_from_object(vm, value)? },)*
$(ArrayContentType::$n(v) => { v[i] = $t::try_into_from_object(vm, value)? },)*
}
Ok(())
}
@@ -264,6 +272,44 @@ def_array_enum!(
(Double, f64, 'd'),
);
trait TryIntoFromObject: Sized {
fn try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self>;
}
macro_rules! adapt_try_into_from_object {
($(($t:ty, $f: path),)*) => {$(
impl TryIntoFromObject for $t {
fn try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
$f(vm, obj)
}
}
)*};
}
adapt_try_into_from_object!(
(i8, i8::try_from_object),
(u8, u8::try_from_object),
(i16, i16::try_from_object),
(u16, u16::try_from_object),
(i32, i32::try_from_object),
(u32, u32::try_from_object),
(i64, i64::try_from_object),
(u64, u64::try_from_object),
(f32, f32_try_into_from_object),
(f64, f64_try_into_from_object),
);
fn f32_try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<f32> {
try_float(&obj, vm)?
.map(|x| x as f32)
.ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", obj.class().name)))
}
fn f64_try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<f64> {
try_float(&obj, vm)?
.ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", obj.class().name)))
}
#[pyclass(module = "array", name = "array")]
#[derive(Debug)]
pub struct PyArray {
@@ -364,9 +410,7 @@ impl PyArray {
#[pymethod]
fn index(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
self.borrow_value()
.index(x, vm)?
.ok_or_else(|| vm.new_value_error("x not in array".to_owned()))
self.borrow_value().index(x, vm)
}
#[pymethod]