Use static ref

This commit is contained in:
Jeong Yunwon
2022-05-30 06:54:56 +09:00
parent ea95777ec7
commit 09fc676164
6 changed files with 95 additions and 77 deletions

View File

@@ -59,11 +59,11 @@ impl From<f64> for PyFloat {
impl PyObject {
pub fn try_float_opt(&self, vm: &VirtualMachine) -> PyResult<Option<PyRef<PyFloat>>> {
PyNumber::from(self).float_opt(vm)
PyNumber::new(self, vm).float_opt(vm)
}
pub fn try_float(&self, vm: &VirtualMachine) -> PyResult<PyRef<PyFloat>> {
PyNumber::from(self).float(vm)
PyNumber::new(self, vm).float(vm)
}
}

View File

@@ -265,7 +265,7 @@ impl Constructor for PyInt {
val
};
PyNumber::from(val.as_ref())
PyNumber::new(val.as_ref(), vm)
.int(vm)
.map(|x| x.as_bigint().clone())
}

View File

@@ -82,7 +82,7 @@ impl Deref for ArgIntoFloat {
impl TryFromObject for ArgIntoFloat {
// Equivalent to PyFloat_AsDouble.
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let value = PyNumber::from(obj.as_ref()).float(vm)?.to_f64();
let value = PyNumber::new(obj.as_ref(), vm).float(vm)?.to_f64();
Ok(ArgIntoFloat { value })
}
}

View File

@@ -1,8 +1,5 @@
use std::borrow::Cow;
use crate::{
builtins::{int, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr},
common::lock::OnceCell,
function::ArgBytesLike,
stdlib::warnings,
AsObject, PyObject, PyPayload, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine,
@@ -100,45 +97,42 @@ impl PyNumberMethods {
pub struct PyNumber<'a> {
pub obj: &'a PyObject,
// some fast path do not need methods, so we do lazy initialize
methods: OnceCell<Cow<'static, PyNumberMethods>>,
pub methods: Option<&'static PyNumberMethods>,
}
impl<'a> From<&'a PyObject> for PyNumber<'a> {
fn from(obj: &'a PyObject) -> Self {
impl<'a> PyNumber<'a> {
pub fn new(obj: &'a PyObject, vm: &VirtualMachine) -> Self {
Self {
obj,
methods: OnceCell::new(),
methods: Self::find_methods(obj, vm),
}
}
}
impl PyNumber<'_> {
pub fn methods(&self, vm: &VirtualMachine) -> &PyNumberMethods {
&*self.methods_cow(vm)
pub fn find_methods(obj: &PyObject, vm: &VirtualMachine) -> Option<&'static PyNumberMethods> {
obj.class()
.mro_find_map(|x| x.slots.as_number.load())
.map(|f| f(obj, vm))
}
pub fn methods_cow(&self, vm: &VirtualMachine) -> &Cow<'static, PyNumberMethods> {
self.methods.get_or_init(|| {
self.obj
.class()
.mro_find_map(|x| x.slots.as_number.load())
.map(|f| f(self.obj, vm))
.unwrap_or_else(|| Cow::Borrowed(&PyNumberMethods::NOT_IMPLEMENTED))
})
pub fn methods(&self) -> &'static PyNumberMethods {
self.methods.unwrap_or(&PyNumberMethods::NOT_IMPLEMENTED)
}
// PyNumber_Check
pub fn check(&self, vm: &VirtualMachine) -> bool {
let methods = self.methods(vm);
methods.int.is_some()
|| methods.index.is_some()
|| methods.float.is_some()
|| self.obj.payload_is::<PyComplex>()
pub fn check(obj: &PyObject, vm: &VirtualMachine) -> bool {
Self::find_methods(obj, vm).map_or(false, |methods| {
methods.int.is_some()
|| methods.index.is_some()
|| methods.float.is_some()
|| obj.payload_is::<PyComplex>()
})
}
// PyIndex_Check
pub fn is_index(&self, vm: &VirtualMachine) -> bool {
self.methods(vm).index.is_some()
pub fn is_index(&self) -> bool {
self.methods().index.is_some()
}
pub fn int(&self, vm: &VirtualMachine) -> PyResult<PyIntRef> {
@@ -156,7 +150,7 @@ impl PyNumber<'_> {
if let Some(i) = self.obj.downcast_ref_if_exact::<PyInt>(vm) {
Ok(i.to_owned())
} else if let Some(f) = self.methods(vm).int {
} else if let Some(f) = self.methods().int {
let ret = f(self, vm)?;
if !ret.class().is(PyInt::class(vm)) {
warnings::warn(
@@ -174,7 +168,7 @@ impl PyNumber<'_> {
} else {
Ok(ret)
}
} else if self.methods(vm).index.is_some() {
} else if self.methods().index.is_some() {
self.index(vm)
} else if let Ok(Ok(f)) =
vm.get_special_method(self.obj.to_owned(), identifier!(vm, __trunc__))
@@ -187,7 +181,7 @@ impl PyNumber<'_> {
// vm,
// )?;
let ret = f.invoke((), vm)?;
PyNumber::from(ret.as_ref()).index(vm).map_err(|_| {
PyNumber::new(ret.as_ref(), vm).index(vm).map_err(|_| {
vm.new_type_error(format!(
"__trunc__ returned non-Integral (type {})",
ret.class()
@@ -215,7 +209,7 @@ impl PyNumber<'_> {
Ok(Some(i.to_owned()))
} else if let Some(i) = self.obj.payload::<PyInt>() {
Ok(Some(vm.ctx.new_bigint(i.as_bigint())))
} else if let Some(f) = self.methods(vm).index {
} else if let Some(f) = self.methods().index {
let ret = f(self, vm)?;
if !ret.class().is(PyInt::class(vm)) {
warnings::warn(
@@ -250,7 +244,7 @@ impl PyNumber<'_> {
pub fn float_opt(&self, vm: &VirtualMachine) -> PyResult<Option<PyRef<PyFloat>>> {
if let Some(float) = self.obj.downcast_ref_if_exact::<PyFloat>(vm) {
Ok(Some(float.to_owned()))
} else if let Some(f) = self.methods(vm).float {
} else if let Some(f) = self.methods().float {
let ret = f(self, vm)?;
if !ret.class().is(PyFloat::class(vm)) {
warnings::warn(
@@ -268,7 +262,7 @@ impl PyNumber<'_> {
} else {
Ok(Some(ret))
}
} else if self.methods(vm).index.is_some() {
} else if self.methods().index.is_some() {
let i = self.index(vm)?;
let value = int::try_to_float(i.as_bigint(), vm)?;
Ok(Some(vm.ctx.new_float(value)))

View File

@@ -139,7 +139,7 @@ impl Default for PyTypeFlags {
pub(crate) type GenericMethod = fn(&PyObject, FuncArgs, &VirtualMachine) -> PyResult;
pub(crate) type AsMappingFunc = fn(&PyObject, &VirtualMachine) -> &'static PyMappingMethods;
pub(crate) type AsNumberFunc = fn(&PyObject, &VirtualMachine) -> Cow<'static, PyNumberMethods>;
pub(crate) type AsNumberFunc = fn(&PyObject, &VirtualMachine) -> &'static PyNumberMethods;
pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyHash>;
// CallFunc = GenericMethod
pub(crate) type GetattroFunc = fn(&PyObject, PyStrRef, &VirtualMachine) -> PyResult;
@@ -340,43 +340,65 @@ fn as_sequence_generic(zelf: &PyObject, vm: &VirtualMachine) -> &'static PySeque
static_as_sequence_generic(has_length, has_ass_item)
}
fn as_number_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> Cow<'static, PyNumberMethods> {
Cow::Owned(PyNumberMethods {
int: then_some_closure!(
zelf.class().has_attr(identifier!(vm, __int__)),
|num, vm| {
let ret =
vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?;
ret.downcast::<PyInt>().map_err(|obj| {
vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class()))
})
}
),
float: then_some_closure!(
zelf.class().has_attr(identifier!(vm, __float__)),
|num, vm| {
let ret =
vm.call_special_method(num.obj.to_owned(), identifier!(vm, __float__), ())?;
ret.downcast::<PyFloat>().map_err(|obj| {
vm.new_type_error(format!(
"__float__ returned non-float (type {})",
obj.class()
))
})
}
),
index: then_some_closure!(
zelf.class().has_attr(identifier!(vm, __index__)),
|num, vm| {
let ret =
vm.call_special_method(num.obj.to_owned(), identifier!(vm, __index__), ())?;
ret.downcast::<PyInt>().map_err(|obj| {
vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class()))
})
}
),
..PyNumberMethods::NOT_IMPLEMENTED
})
pub(crate) fn static_as_number_generic(
has_int: bool,
has_float: bool,
has_index: bool,
) -> &'static PyNumberMethods {
static METHODS: &[PyNumberMethods] = &[
new_generic(false, false, false),
new_generic(true, false, false),
new_generic(false, true, false),
new_generic(true, true, false),
new_generic(false, false, true),
new_generic(true, false, true),
new_generic(false, true, true),
new_generic(true, true, true),
];
fn int(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyInt>> {
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?;
ret.downcast::<PyInt>().map_err(|obj| {
vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class()))
})
}
fn float(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyFloat>> {
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __float__), ())?;
ret.downcast::<PyFloat>().map_err(|obj| {
vm.new_type_error(format!(
"__float__ returned non-float (type {})",
obj.class()
))
})
}
fn index(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyInt>> {
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __index__), ())?;
ret.downcast::<PyInt>().map_err(|obj| {
vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class()))
})
}
const fn new_generic(has_int: bool, has_float: bool, has_index: bool) -> PyNumberMethods {
PyNumberMethods {
int: if has_int { Some(int) } else { None },
float: if has_float { Some(float) } else { None },
index: if has_index { Some(index) } else { None },
..PyNumberMethods::NOT_IMPLEMENTED
}
}
let key = bool_int(has_int) | (bool_int(has_float) << 1) | (bool_int(has_index) << 2);
&METHODS[key]
}
fn as_number_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> &'static PyNumberMethods {
let (has_int, has_float, has_index) = (
zelf.class().has_attr(identifier!(vm, __int__)),
zelf.class().has_attr(identifier!(vm, __float__)),
zelf.class().has_attr(identifier!(vm, __index__)),
);
static_as_number_generic(has_int, has_float, has_index)
}
fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
@@ -1041,8 +1063,8 @@ pub trait AsNumber: PyPayload {
#[inline]
#[pyslot]
fn as_number(_zelf: &PyObject, _vm: &VirtualMachine) -> Cow<'static, PyNumberMethods> {
Cow::Borrowed(&Self::AS_NUMBER)
fn as_number(_zelf: &PyObject, _vm: &VirtualMachine) -> &'static PyNumberMethods {
&Self::AS_NUMBER
}
fn number_downcast<'a>(number: &'a PyNumber) -> &'a Py<Self> {

View File

@@ -10,11 +10,13 @@ use crate::{
/// Collection of operators
impl VirtualMachine {
pub fn to_index_opt(&self, obj: PyObjectRef) -> Option<PyResult<PyIntRef>> {
PyNumber::from(obj.as_ref()).index_opt(self).transpose()
PyNumber::new(obj.as_ref(), self)
.index_opt(self)
.transpose()
}
pub fn to_index(&self, obj: &PyObject) -> PyResult<PyIntRef> {
PyNumber::from(obj).index(self)
PyNumber::new(obj, self).index(self)
}
#[inline]