Skip to content

Commit

Permalink
Add HashTrieMap.convert, a faster way to convert to it.
Browse files Browse the repository at this point in the history
Replaces manually doing things like:

    value if isinstance(value, HashTrieMap) else HashTrieMap(value)

which can cause ~2x slowdowns (and was the case also with pyrsistent)
  • Loading branch information
Julian committed Mar 4, 2023
1 parent 9c50caf commit 7588d2f
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rpds-py"
version = "0.3.0"
version = "0.4.0"
edition = "2021"

[lib]
Expand Down
5 changes: 5 additions & 0 deletions rpds.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class HashTrieMap(Mapping[KT, VT]):
def remove(self, key: KT) -> "HashTrieMap[KT, VT]": ...
def insert(self, key: KT, val: VT) -> "HashTrieMap[KT, VT]": ...
def update(self, *args: Mapping): ...
@classmethod
def convert(
cls,
value: Mapping[KT, VT] | Iterable[tuple[KT, VT]],
) -> "HashTrieMap[KT, VT]": ...

class HashTrieSet(FrozenSet[T]):
def __init__(self, value: Iterable[T] = ()): ...
Expand Down
11 changes: 10 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::vec::IntoIter;

use pyo3::exceptions::PyIndexError;
use pyo3::pyclass::CompareOp;
use pyo3::types::{PyDict, PyIterator, PyTuple};
use pyo3::types::{PyDict, PyIterator, PyTuple, PyType};
use pyo3::{exceptions::PyKeyError, types::PyMapping};
use pyo3::{prelude::*, AsPyPointer};
use rpds::{HashTrieMap, HashTrieSet, List};
Expand Down Expand Up @@ -153,6 +153,15 @@ impl HashTrieMapPy {
}
}

#[classmethod]
fn convert(_cls: &PyType, value: &PyAny, py: Python) -> PyResult<PyObject> {
if value.is_instance_of::<HashTrieMapPy>()? {
Ok(value.into())
} else {
Ok(HashTrieMapPy::extract(value)?.into_py(py))
}
}

fn get(&self, key: Key) -> Option<&PyObject> {
self.inner.get(&key)
}
Expand Down
10 changes: 10 additions & 0 deletions tests/test_hash_trie_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,13 @@ def test_empty_truthiness():
def test_iterable():
m = HashTrieMap((i, i * 2) for i in range(3))
assert m == HashTrieMap({0: 0, 1: 2, 2: 4})


def test_convert_hashtriemap():
m = HashTrieMap({i: i * 2 for i in range(3)})
assert HashTrieMap.convert({i: i * 2 for i in range(3)}) == m


def test_fast_convert_hashtriemap():
m = HashTrieMap({i: i * 2 for i in range(3)})
assert HashTrieMap.convert(m) is m

0 comments on commit 7588d2f

Please sign in to comment.