|
1 | 1 | use std::borrow::{Borrow, Cow};
|
2 |
| -use std::sync::Arc; |
| 2 | +use std::sync::{Arc, Mutex}; |
3 | 3 |
|
4 | 4 | use chrono::{
|
5 | 5 | DateTime, Datelike, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, TimeDelta, Timelike,
|
6 | 6 | };
|
7 | 7 | use chrono_tz::Tz;
|
| 8 | +use hashbrown::HashMap; |
8 | 9 | #[cfg(feature = "object")]
|
9 | 10 | use polars::chunked_array::object::PolarsObjectSafe;
|
10 | 11 | #[cfg(feature = "object")]
|
11 | 12 | use polars::datatypes::OwnedObject;
|
12 |
| -use polars::datatypes::{DataType, Field, PlHashMap, TimeUnit}; |
| 13 | +use polars::datatypes::{DataType, Field, TimeUnit}; |
13 | 14 | use polars::prelude::{AnyValue, PlSmallStr, Series};
|
14 | 15 | use polars_core::utils::any_values_to_supertype_and_n_dtypes;
|
15 | 16 | use polars_core::utils::arrow::temporal_conversions::date32_to_date;
|
| 17 | +use polars_utils::aliases::PlFixedStateQuality; |
16 | 18 | use pyo3::exceptions::{PyOverflowError, PyTypeError, PyValueError};
|
17 | 19 | use pyo3::prelude::*;
|
18 | 20 | use pyo3::pybacked::PyBackedStr;
|
@@ -186,8 +188,8 @@ impl std::hash::Hash for TypeObjectKey {
|
186 | 188 | }
|
187 | 189 |
|
188 | 190 | type InitFn = for<'py> fn(&Bound<'py, PyAny>, bool) -> PyResult<AnyValue<'py>>;
|
189 |
| -pub(crate) static LUT: crate::gil_once_cell::GILOnceCell<PlHashMap<TypeObjectKey, InitFn>> = |
190 |
| - crate::gil_once_cell::GILOnceCell::new(); |
| 191 | +pub(crate) static LUT: Mutex<HashMap<TypeObjectKey, InitFn, PlFixedStateQuality>> = |
| 192 | + Mutex::new(HashMap::with_hasher(PlFixedStateQuality::with_seed(0))); |
191 | 193 |
|
192 | 194 | /// Convert a Python object to an [`AnyValue`].
|
193 | 195 | pub(crate) fn py_object_to_any_value<'py>(
|
@@ -474,11 +476,8 @@ pub(crate) fn py_object_to_any_value<'py>(
|
474 | 476 | ///
|
475 | 477 | /// Note: This function is only ran if the object's type is not already in the
|
476 | 478 | /// lookup table.
|
477 |
| - fn get_conversion_function( |
478 |
| - ob: &Bound<'_, PyAny>, |
479 |
| - py: Python<'_>, |
480 |
| - allow_object: bool, |
481 |
| - ) -> PyResult<InitFn> { |
| 479 | + fn get_conversion_function(ob: &Bound<'_, PyAny>, allow_object: bool) -> PyResult<InitFn> { |
| 480 | + let py = ob.py(); |
482 | 481 | if ob.is_none() {
|
483 | 482 | Ok(get_null)
|
484 | 483 | }
|
@@ -549,20 +548,18 @@ pub(crate) fn py_object_to_any_value<'py>(
|
549 | 548 | let py_type = ob.get_type();
|
550 | 549 | let py_type_address = py_type.as_ptr() as usize;
|
551 | 550 |
|
552 |
| - Python::with_gil(move |py| { |
553 |
| - LUT.with_gil(py, move |lut| { |
554 |
| - if !lut.contains_key(&py_type_address) { |
555 |
| - let k = TypeObjectKey::new(py_type.clone().unbind()); |
556 |
| - |
557 |
| - assert_eq!(k.address, py_type_address); |
| 551 | + let conversion_func = { |
| 552 | + if let Some(cached_func) = LUT.lock().unwrap().get(&py_type_address) { |
| 553 | + *cached_func |
| 554 | + } else { |
| 555 | + let k = TypeObjectKey::new(py_type.clone().unbind()); |
| 556 | + assert_eq!(k.address, py_type_address); |
558 | 557 |
|
559 |
| - unsafe { |
560 |
| - lut.insert_unique_unchecked(k, get_conversion_function(ob, py, allow_object)?); |
561 |
| - } |
562 |
| - } |
| 558 | + let func = get_conversion_function(ob, allow_object)?; |
| 559 | + LUT.lock().unwrap().insert(k, func); |
| 560 | + func |
| 561 | + } |
| 562 | + }; |
563 | 563 |
|
564 |
| - let conversion_func = *lut.get(&py_type_address).unwrap(); |
565 |
| - conversion_func(ob, strict) |
566 |
| - }) |
567 |
| - }) |
| 564 | + conversion_func(ob, strict) |
568 | 565 | }
|
0 commit comments