Skip to content

Commit

Permalink
skip slow path on 3.8+
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Jan 14, 2024
1 parent 778f592 commit 4a97ccb
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 15 deletions.
2 changes: 1 addition & 1 deletion newsfragments/3742.changed.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Improve performance of `extract::<i64>` (and other integer types) by checking if types are a `PyLong` and if so avoiding calling `__index__()` before converting the value to an integer, matching the current behavior of `extract::<BigInt>()`. Gives performance improvement of around 30% for successful extraction.
Improve performance of `extract::<i64>` (and other integer types) by avoiding call to `__index__()` converting the value to an integer for 3.8+. Gives performance improvement of around 30% for successful extraction.
39 changes: 25 additions & 14 deletions src/conversions/std/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,32 @@ macro_rules! int_fits_c_long {

impl<'source> FromPyObject<'source> for $rust_type {
fn extract(obj: &'source PyAny) -> PyResult<Self> {
// fast path - checking for subclass of `int` just checks a bit in the type object
let val = if let Ok(long) = obj.downcast::<PyLong>() {
err_if_invalid_value(obj.py(), -1, unsafe { ffi::PyLong_AsLong(long.as_ptr()) })
} else {
unsafe {
let num = ffi::PyNumber_Index(obj.as_ptr());
if num.is_null() {
Err(PyErr::fetch(obj.py()))
} else {
let val = err_if_invalid_value(obj.py(), -1, ffi::PyLong_AsLong(num));
ffi::Py_DECREF(num);
val
let val: c_long;
// with python 3.8+ PyLong_AsLong takes care of calling PyNumber_Index itself
// hence no need for the slow `PyNumber_Index` path
// see https://github.com/PyO3/pyo3/pull/3742 for detials.
#[cfg(Py_3_8)]
{
val = err_if_invalid_value(obj.py(), -1, unsafe { ffi::PyLong_AsLong(obj.as_ptr()) })?;
}
#[cfg(not(Py_3_8))]
{
val = if let Ok(long) = obj.downcast::<PyLong>() {
// fast path - checking for subclass of `int` just checks a bit in the type object
err_if_invalid_value(obj.py(), -1, unsafe { ffi::PyLong_AsLong(long.as_ptr()) })
} else {
unsafe {
let num = ffi::PyNumber_Index(obj.as_ptr());
if num.is_null() {
Err(PyErr::fetch(obj.py()))
} else {
let val = err_if_invalid_value(obj.py(), -1, ffi::PyLong_AsLong(num));
ffi::Py_DECREF(num);
val
}
}
}
}?;
}?;
}
<$rust_type>::try_from(val)
.map_err(|e| exceptions::PyOverflowError::new_err(e.to_string()))
}
Expand Down

0 comments on commit 4a97ccb

Please sign in to comment.