Skip to content

Commit

Permalink
add support for verbatims in ketrees (#706)
Browse files Browse the repository at this point in the history
* add support for verbatims in ketrees

* add nodes_including iterator for unshared ownership ketrees

* add nodes_including iterator for shared ownership ketrees

* Improve documentation for KeTrees

* Improve documentation for KeTree nodes
  • Loading branch information
p-avital authored Feb 7, 2024
1 parent 6ecb009 commit 634ad71
Show file tree
Hide file tree
Showing 15 changed files with 1,016 additions and 159 deletions.
26 changes: 24 additions & 2 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ description = "Zenoh: Zero Overhead Pub/sub, Store/Query and Compute."
# (https://github.com/rust-lang/cargo/issues/11329)
[workspace.dependencies]
aes = "0.8.2"
ahash = "0.8.7"
anyhow = { version = "1.0.69", default-features = false } # Default features are disabled due to usage in no_std crates
async-executor = "1.5.0"
async-global-executor = "2.3.1"
Expand Down
1 change: 1 addition & 0 deletions commons/zenoh-keyexpr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ hashbrown = { workspace = true }

# NOTE: May cause problems when testing no_std stuff. Check this tool: https://docs.rs/crate/cargo-no-dev-deps/0.1.0
[dev-dependencies]
ahash = { workspace = true }
criterion = { workspace = true }
lazy_static = { workspace = true }
rand = { workspace = true, features = ["default"] }
Expand Down
20 changes: 17 additions & 3 deletions commons/zenoh-keyexpr/benches/keyexpr_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ fn main() {
let mut intersections = Averager::default();
let results = Benchmarker::benchmark(|b| {
let keys = KeySet::generate(total, wildness, no_double_stars);
let mut ketree: KeBoxTree<_> = KeBoxTree::new();
let mut vectree: KeBoxTree<_, bool, VecSetProvider> = KeBoxTree::new();
let mut hashtree: KeBoxTree<_, bool, HashMapProvider> = KeBoxTree::new();
let mut ketree = KeBoxTree::new();
let mut vectree: KeBoxTree<_, bool, VecSetProvider> = KeBoxTree::default();
let mut hashtree: KeBoxTree<_, bool, HashMapProvider> = KeBoxTree::default();
let mut ahashtree: KeBoxTree<_, bool, HashMapProvider<ahash::AHasher>> =
KeBoxTree::default();
let (kearctree, mut token): (KeArcTree<i32>, _) = KeArcTree::new().unwrap();
let mut map = HashMap::new();
for key in keys.iter() {
Expand All @@ -58,13 +60,15 @@ fn main() {
});
b.run_once("vectree_insert", || vectree.insert(key, 0));
b.run_once("hashtree_insert", || hashtree.insert(key, 0));
b.run_once("ahashtree_insert", || ahashtree.insert(key, 0));
b.run_once("hashmap_insert", || map.insert(key.to_owned(), 0));
}
for key in keys.iter() {
b.run_once("ketree_fetch", || ketree.node(key));
b.run_once("kearctree_fetch", || kearctree.node(&token, key));
b.run_once("vectree_fetch", || vectree.node(key));
b.run_once("hashtree_fetch", || hashtree.node(key));
b.run_once("ahashtree_fetch", || ahashtree.node(key));
b.run_once("hashmap_fetch", || map.get(key));
}
for key in keys.iter() {
Expand All @@ -81,6 +85,9 @@ fn main() {
b.run_once("hashtree_intersect", || {
hashtree.intersecting_nodes(key).count()
});
b.run_once("ahashtree_intersect", || {
ahashtree.intersecting_nodes(key).count()
});
b.run_once("hashmap_intersect", || {
map.iter().filter(|(k, _)| key.intersects(k)).count()
});
Expand All @@ -92,6 +99,9 @@ fn main() {
});
b.run_once("vectree_include", || vectree.included_nodes(key).count());
b.run_once("hashtree_include", || hashtree.included_nodes(key).count());
b.run_once("ahashtree_include", || {
ahashtree.included_nodes(key).count()
});
b.run_once("hashmap_include", || {
map.iter().filter(|(k, _)| key.includes(k)).count()
});
Expand All @@ -102,21 +112,25 @@ fn main() {
"kearctree_insert",
"vectree_insert",
"hashtree_insert",
"ahashtree_insert",
"hashmap_insert",
"ketree_fetch",
"kearctree_fetch",
"vectree_fetch",
"hashtree_fetch",
"ahashtree_fetch",
"hashmap_fetch",
"ketree_intersect",
"kearctree_intersect",
"vectree_intersect",
"hashtree_intersect",
"ahashtree_intersect",
"hashmap_intersect",
"ketree_include",
"kearctree_include",
"vectree_include",
"hashtree_include",
"ahashtree_include",
"hashmap_include",
] {
let b = results.benches.get(name).unwrap();
Expand Down
5 changes: 4 additions & 1 deletion commons/zenoh-keyexpr/src/key_expr/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use super::OwnedKeyExpr;

fn random_chunk(rng: &'_ mut impl rand::Rng) -> impl Iterator<Item = u8> + '_ {
let n = rng.gen_range(1..3);
(0..n).map(move |_| rng.sample(rand::distributions::Uniform::from(b'a'..b'c')))
rng.gen_bool(0.05)
.then_some(b'@')
.into_iter()
.chain((0..n).map(move |_| rng.sample(rand::distributions::Uniform::from(b'a'..b'c'))))
}

fn make(ke: &mut Vec<u8>, rng: &mut impl rand::Rng) {
Expand Down
62 changes: 61 additions & 1 deletion commons/zenoh-keyexpr/src/keyexpr_tree/arc_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ fn ketree_borrow_mut<'a, T, Token: TokenTrait>(
/// A shared KeTree.
///
/// The tree and its nodes have shared ownership, while their mutability is managed through the `Token`.
/// The `(node, &token)` tuple implements [`core::ops::Deref`], while `(node, &mut token)` implements [`core::ops::DerefMut`].
///
/// Most of its methods are declared in the [`ITokenKeyExprTree`] trait.
pub struct KeArcTree<
Weight,
Token: TokenTrait = DefaultToken,
Expand All @@ -82,6 +83,14 @@ impl<
> KeArcTree<Weight, DefaultToken, Wildness, Children>
{
/// Constructs the KeArcTree, returning it and its token, unless constructing the Token failed.
///
/// # Type inference papercut
/// Despite some of `KeArcTree`'s generic parameters having default values, those are only taken into
/// account by the compiler when a type is named with some parameters omitted, and not when a type is
/// infered with the same parameters unconstrained.
///
/// The simplest way to resolve this is to eventually assign to tree part of the return value
/// to a variable or field whose type is named `KeArcTree<_>` (the `Weight` parameter can generally be infered).
pub fn new() -> Result<(Self, DefaultToken), <DefaultToken as TokenTrait>::ConstructionError> {
let token = DefaultToken::new()?;
Ok((Self::with_token(&token), token))
Expand Down Expand Up @@ -329,6 +338,57 @@ where
IterOrOption::Opt(self.node_mut(token, key).map(Into::into))
}
}

type IncluderItem = Self::Node;
type Includer = IterOrOption<
TokenPacker<
Includer<
'a,
Children,
Arc<TokenCell<KeArcTreeNode<Weight, Weak<()>, Wildness, Children, Token>, Token>>,
Weight,
>,
&'a Token,
>,
Self::IncluderItem,
>;
fn nodes_including(&'a self, token: &'a Token, key: &'a keyexpr) -> Self::Includer {
let inner = ketree_borrow(&self.inner, token);
if inner.wildness.get() || key.is_wild() {
IterOrOption::Iter(TokenPacker {
iter: Includer::new(&inner.children, key),
token,
})
} else {
IterOrOption::Opt(self.node(token, key))
}
}
type IncluderItemMut = Self::TreeIterItemMut;
type IncluderMut = IterOrOption<
TokenPacker<
Includer<
'a,
Children,
Arc<TokenCell<KeArcTreeNode<Weight, Weak<()>, Wildness, Children, Token>, Token>>,
Weight,
>,
&'a mut Token,
>,
Self::IncluderItemMut,
>;
fn nodes_including_mut(&'a self, token: &'a mut Token, key: &'a keyexpr) -> Self::IncluderMut {
let inner = ketree_borrow(&self.inner, token);
if inner.wildness.get() || key.is_wild() {
unsafe {
IterOrOption::Iter(TokenPacker {
iter: Includer::new(core::mem::transmute(&inner.children), key),
token,
})
}
} else {
IterOrOption::Opt(self.node_mut(token, key).map(Into::into))
}
}
type PruneNode = KeArcTreeNode<Weight, Weak<()>, Wildness, Children, Token>;

fn prune_where<F: FnMut(&mut Self::PruneNode) -> bool>(
Expand Down
48 changes: 38 additions & 10 deletions commons/zenoh-keyexpr/src/keyexpr_tree/box_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use super::impls::KeyedSetProvider;
use super::support::IterOrOption;

/// A fully owned KeTree.
///
/// Note that most of `KeBoxTree`'s methods are declared in the [`IKeyExprTree`] and [`IKeyExprTreeMut`] traits.
#[repr(C)]
pub struct KeBoxTree<
Weight,
Expand All @@ -37,17 +39,13 @@ pub struct KeBoxTree<
wildness: Wildness,
}

impl<
Weight,
Wildness: IWildness,
Children: IChildrenProvider<Box<KeyExprTreeNode<Weight, Wildness, Children>>>,
> KeBoxTree<Weight, Wildness, Children>
impl<Weight> KeBoxTree<Weight, bool, DefaultChildrenProvider>
where
DefaultChildrenProvider:
IChildrenProvider<Box<KeyExprTreeNode<Weight, bool, DefaultChildrenProvider>>>,
{
pub fn new() -> Self {
KeBoxTree {
children: Default::default(),
wildness: Wildness::non_wild(),
}
Default::default()
}
}
impl<
Expand All @@ -57,7 +55,10 @@ impl<
> Default for KeBoxTree<Weight, Wildness, Children>
{
fn default() -> Self {
Self::new()
KeBoxTree {
children: Default::default(),
wildness: Wildness::non_wild(),
}
}
}

Expand Down Expand Up @@ -117,6 +118,20 @@ where
IterOrOption::Opt(node)
}
}

type IncluderItem = <Self::Includer as Iterator>::Item;
type Includer = IterOrOption<
Includer<'a, Children, Box<KeyExprTreeNode<Weight, Wildness, Children>>, Weight>,
&'a Self::Node,
>;
fn nodes_including(&'a self, ke: &'a keyexpr) -> Self::Includer {
if self.wildness.get() || ke.is_wild() {
Includer::new(&self.children, ke).into()
} else {
let node = self.node(ke);
IterOrOption::Opt(node)
}
}
}
impl<
'a,
Expand Down Expand Up @@ -218,6 +233,19 @@ where
IterOrOption::Opt(node)
}
}
type IncluderItemMut = <Self::IncluderMut as Iterator>::Item;
type IncluderMut = IterOrOption<
IncluderMut<'a, Children, Box<KeyExprTreeNode<Weight, Wildness, Children>>, Weight>,
&'a mut Self::Node,
>;
fn nodes_including_mut(&'a mut self, ke: &'a keyexpr) -> Self::IncluderMut {
if self.wildness.get() || ke.is_wild() {
IncluderMut::new(&mut self.children, ke).into()
} else {
let node = self.node_mut(ke);
IterOrOption::Opt(node)
}
}

fn prune_where<F: FnMut(&mut Self::Node) -> bool>(&mut self, mut predicate: F) {
let mut wild = false;
Expand Down
Loading

0 comments on commit 634ad71

Please sign in to comment.