From 537dc8021e5c68a1797fcc139e2f49ddbabbe540 Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Wed, 1 May 2024 16:39:39 +0200 Subject: [PATCH] perf(flatten): fewer clones --- src/flatten.rs | 65 +++++++++++++++++------------------------------ src/tree_state.rs | 2 +- 2 files changed, 24 insertions(+), 43 deletions(-) diff --git a/src/flatten.rs b/src/flatten.rs index 9efe03e..9388a7d 100644 --- a/src/flatten.rs +++ b/src/flatten.rs @@ -18,21 +18,12 @@ impl<'a, Identifier> Flattened<'a, Identifier> { } /// Get a flat list of all visible [`TreeItem`]s. +/// +/// `current` starts empty: `&[]` #[must_use] pub fn flatten<'a, Identifier>( opened: &HashSet>, items: &'a [TreeItem<'a, Identifier>], -) -> Vec> -where - Identifier: Clone + PartialEq + Eq + core::hash::Hash, -{ - internal(opened, items, &[]) -} - -#[must_use] -fn internal<'a, Identifier>( - opened: &HashSet>, - items: &'a [TreeItem<'a, Identifier>], current: &[Identifier], ) -> Vec> where @@ -43,68 +34,58 @@ where let mut child_identifier = current.to_vec(); child_identifier.push(item.identifier.clone()); + let child_result = opened + .contains(&child_identifier) + .then(|| flatten(opened, &item.children, &child_identifier)); + result.push(Flattened { + identifier: child_identifier, item, - identifier: child_identifier.clone(), }); - if opened.contains(&child_identifier) { - let mut child_result = internal(opened, &item.children, &child_identifier); + if let Some(mut child_result) = child_result { result.append(&mut child_result); } } result } +#[cfg(test)] +fn flatten_works(opened: &HashSet>, expected: &[&str]) { + let items = TreeItem::example(); + let result = flatten(opened, &items, &[]); + let actual = result + .into_iter() + .map(|flattened| flattened.identifier.into_iter().last().unwrap()) + .collect::>(); + assert_eq!(actual, expected); +} + #[test] fn get_opened_nothing_opened_is_top_level() { - let items = TreeItem::example(); let opened = HashSet::new(); - let result = flatten(&opened, &items); - let result_text = result - .into_iter() - .map(|flattened| flattened.item.identifier) - .collect::>(); - assert_eq!(result_text, ["a", "b", "h"]); + flatten_works(&opened, &["a", "b", "h"]); } #[test] fn get_opened_wrong_opened_is_only_top_level() { - let items = TreeItem::example(); let mut opened = HashSet::new(); opened.insert(vec!["a"]); opened.insert(vec!["b", "d"]); - let result = flatten(&opened, &items); - let result_text = result - .into_iter() - .map(|flattened| flattened.item.identifier) - .collect::>(); - assert_eq!(result_text, ["a", "b", "h"]); + flatten_works(&opened, &["a", "b", "h"]); } #[test] fn get_opened_one_is_opened() { - let items = TreeItem::example(); let mut opened = HashSet::new(); opened.insert(vec!["b"]); - let result = flatten(&opened, &items); - let result_text = result - .into_iter() - .map(|flattened| flattened.item.identifier) - .collect::>(); - assert_eq!(result_text, ["a", "b", "c", "d", "g", "h"]); + flatten_works(&opened, &["a", "b", "c", "d", "g", "h"]); } #[test] fn get_opened_all_opened() { - let items = TreeItem::example(); let mut opened = HashSet::new(); opened.insert(vec!["b"]); opened.insert(vec!["b", "d"]); - let result = flatten(&opened, &items); - let result_text = result - .into_iter() - .map(|flattened| flattened.item.identifier) - .collect::>(); - assert_eq!(result_text, ["a", "b", "c", "d", "e", "f", "g", "h"]); + flatten_works(&opened, &["a", "b", "c", "d", "e", "f", "g", "h"]); } diff --git a/src/tree_state.rs b/src/tree_state.rs index 0f70c33..a343675 100644 --- a/src/tree_state.rs +++ b/src/tree_state.rs @@ -51,7 +51,7 @@ where &self, items: &'a [TreeItem<'a, Identifier>], ) -> Vec> { - flatten(&self.opened, items) + flatten(&self.opened, items, &[]) } /// Selects the given identifier.