PyList: remove get_parked_item, use macros for speed on !abi3

This commit is contained in:
Georg Brandl 2021-06-06 07:48:21 +02:00
parent 4d2c173dbe
commit 3bebc19e2d
3 changed files with 33 additions and 52 deletions

View File

@ -68,6 +68,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Remove `__doc__` from module's `__all__`. [#1509](https://github.com/PyO3/pyo3/pull/1509) - Remove `__doc__` from module's `__all__`. [#1509](https://github.com/PyO3/pyo3/pull/1509)
- Remove `PYO3_CROSS_INCLUDE_DIR` environment variable and the associated C header parsing functionality. [#1521](https://github.com/PyO3/pyo3/pull/1521) - Remove `PYO3_CROSS_INCLUDE_DIR` environment variable and the associated C header parsing functionality. [#1521](https://github.com/PyO3/pyo3/pull/1521)
- Remove `raw_pycfunction!` macro. [#1619](https://github.com/PyO3/pyo3/pull/1619) - Remove `raw_pycfunction!` macro. [#1619](https://github.com/PyO3/pyo3/pull/1619)
- Remove `PyList::get_parked_item`. [#1664](https://github.com/PyO3/pyo3/pull/1664)
### Fixed ### Fixed
- Remove FFI definition `PyCFunction_ClearFreeList` for Python 3.9 and later. [#1425](https://github.com/PyO3/pyo3/pull/1425) - Remove FFI definition `PyCFunction_ClearFreeList` for Python 3.9 and later. [#1425](https://github.com/PyO3/pyo3/pull/1425)

View File

@ -51,7 +51,7 @@ impl PyDict {
/// Returns a new dictionary that contains the same key-value pairs as self. /// Returns a new dictionary that contains the same key-value pairs as self.
/// ///
/// This is equivalent to the Python expression `dict(self)`. /// This is equivalent to the Python expression `self.copy()`.
pub fn copy(&self) -> PyResult<&PyDict> { pub fn copy(&self) -> PyResult<&PyDict> {
unsafe { unsafe {
self.py() self.py()

View File

@ -15,6 +15,22 @@ pub struct PyList(PyAny);
pyobject_native_type_core!(PyList, ffi::PyList_Type, #checkfunction=ffi::PyList_Check); pyobject_native_type_core!(PyList, ffi::PyList_Type, #checkfunction=ffi::PyList_Check);
#[inline]
unsafe fn new_from_iter<T>(
elements: impl ExactSizeIterator<Item = T>,
convert: impl Fn(T) -> PyObject,
) -> *mut ffi::PyObject {
let ptr = ffi::PyList_New(elements.len() as Py_ssize_t);
for (i, e) in elements.enumerate() {
let obj = convert(e).into_ptr();
#[cfg(not(Py_LIMITED_API))]
ffi::PyList_SET_ITEM(ptr, i as Py_ssize_t, obj);
#[cfg(Py_LIMITED_API)]
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
ptr
}
impl PyList { impl PyList {
/// Constructs a new list with the given elements. /// Constructs a new list with the given elements.
pub fn new<T, U>(py: Python<'_>, elements: impl IntoIterator<Item = T, IntoIter = U>) -> &PyList pub fn new<T, U>(py: Python<'_>, elements: impl IntoIterator<Item = T, IntoIter = U>) -> &PyList
@ -22,15 +38,8 @@ impl PyList {
T: ToPyObject, T: ToPyObject,
U: ExactSizeIterator<Item = T>, U: ExactSizeIterator<Item = T>,
{ {
let elements_iter = elements.into_iter();
let len = elements_iter.len();
unsafe { unsafe {
let ptr = ffi::PyList_New(len as Py_ssize_t); py.from_owned_ptr::<PyList>(new_from_iter(elements.into_iter(), |e| e.to_object(py)))
for (i, e) in elements_iter.enumerate() {
let obj = e.to_object(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
py.from_owned_ptr::<PyList>(ptr)
} }
} }
@ -41,8 +50,15 @@ impl PyList {
/// Returns the length of the list. /// Returns the length of the list.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
// non-negative Py_ssize_t should always fit into Rust usize unsafe {
unsafe { ffi::PyList_Size(self.as_ptr()) as usize } #[cfg(not(Py_LIMITED_API))]
let size = ffi::PyList_GET_SIZE(self.as_ptr());
#[cfg(Py_LIMITED_API)]
let size = ffi::PyList_Size(self.as_ptr());
// non-negative Py_ssize_t should always fit into Rust usize
size as usize
}
} }
/// Checks if the list is empty. /// Checks if the list is empty.
@ -56,6 +72,9 @@ impl PyList {
pub fn get_item(&self, index: isize) -> &PyAny { pub fn get_item(&self, index: isize) -> &PyAny {
assert!((index.abs() as usize) < self.len()); assert!((index.abs() as usize) < self.len());
unsafe { unsafe {
#[cfg(not(Py_LIMITED_API))]
let ptr = ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t);
#[cfg(Py_LIMITED_API)]
let ptr = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t); let ptr = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t);
// PyList_GetItem return borrowed ptr; must make owned for safety (see #890). // PyList_GetItem return borrowed ptr; must make owned for safety (see #890).
@ -64,18 +83,6 @@ impl PyList {
} }
} }
/// Gets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn get_parked_item(&self, index: isize) -> PyObject {
unsafe {
PyObject::from_borrowed_ptr(
self.py(),
ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t),
)
}
}
/// Sets the item at the specified index. /// Sets the item at the specified index.
/// ///
/// Panics if the index is out of range. /// Panics if the index is out of range.
@ -167,14 +174,7 @@ where
T: ToPyObject, T: ToPyObject,
{ {
fn to_object(&self, py: Python<'_>) -> PyObject { fn to_object(&self, py: Python<'_>) -> PyObject {
unsafe { unsafe { PyObject::from_owned_ptr(py, new_from_iter(self.iter(), |e| e.to_object(py))) }
let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
for (i, e) in self.iter().enumerate() {
let obj = e.to_object(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
PyObject::from_owned_ptr(py, ptr)
}
} }
} }
@ -192,14 +192,7 @@ where
T: IntoPy<PyObject>, T: IntoPy<PyObject>,
{ {
fn into_py(self, py: Python) -> PyObject { fn into_py(self, py: Python) -> PyObject {
unsafe { unsafe { PyObject::from_owned_ptr(py, new_from_iter(self.into_iter(), |e| e.into_py(py))) }
let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
for (i, e) in self.into_iter().enumerate() {
let obj = e.into_py(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
PyObject::from_owned_ptr(py, ptr)
}
} }
} }
@ -244,19 +237,6 @@ mod test {
assert_eq!(7, list.get_item(3).extract::<i32>().unwrap()); assert_eq!(7, list.get_item(3).extract::<i32>().unwrap());
} }
#[test]
fn test_get_parked_item() {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let ob = v.to_object(py);
let list = <PyList as PyTryFrom>::try_from(ob.as_ref(py)).unwrap();
assert_eq!(2, list.get_parked_item(0).extract::<i32>(py).unwrap());
assert_eq!(3, list.get_parked_item(1).extract::<i32>(py).unwrap());
assert_eq!(5, list.get_parked_item(2).extract::<i32>(py).unwrap());
assert_eq!(7, list.get_parked_item(3).extract::<i32>(py).unwrap());
}
#[test] #[test]
fn test_set_item() { fn test_set_item() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();