From 8732e70e931e295ec6708e2229cba25b76048139 Mon Sep 17 00:00:00 2001 From: tiye Date: Thu, 22 Feb 2024 02:15:50 +0800 Subject: [PATCH 1/2] trying with a traverse mathod --- Cargo.toml | 2 +- benches/iterator.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 8 ++++++++ src/tree.rs | 27 +++++++++++++++++++++------ tests/list_tests.rs | 21 +++++++++++++++++++++ 5 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 benches/iterator.rs diff --git a/Cargo.toml b/Cargo.toml index 0b346d6..dfcdcdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ criterion = "0.3" [[bench]] -name = "accessing" +name = "iterator" harness = false [profile.release] diff --git a/benches/iterator.rs b/benches/iterator.rs new file mode 100644 index 0000000..8c553a3 --- /dev/null +++ b/benches/iterator.rs @@ -0,0 +1,38 @@ +use std::cell::RefCell; + +use criterion::{criterion_group, criterion_main, Criterion}; + +use im_ternary_tree::TernaryTreeList; + +const ITER_SIZE: usize = 10000; + +fn criterion_benchmark(c: &mut Criterion) { + let mut data = TernaryTreeList::Empty; + + for idx in 0..ITER_SIZE { + data = data.push(idx) + } + + c.bench_function("iter", |b| { + let mut cc = 0; + + b.iter(|| { + for item in &data { + cc += item; + } + }) + }); + + c.bench_function("traverse", |b| { + let cc = RefCell::new(0); + + b.iter(|| { + data.traverse(|item| { + *cc.borrow_mut() += item; + }); + }) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs index 1db71c4..819a197 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -451,6 +451,14 @@ where } } + /// traverse all elements in list, use referenced value + pub fn traverse(&self, f: impl Fn(&T)) { + match self { + Empty => (), + Tree(t) => t.traverse(&f), + } + } + pub fn iter(&self) -> TernaryTreeListRefIntoIterator { TernaryTreeListRefIntoIterator { value: self, diff --git a/src/tree.rs b/src/tree.rs index d809f0d..52fcd5a 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -1240,8 +1240,23 @@ where xs } - pub fn iter(&self) -> TernaryTreeRefIntoIterator { - TernaryTreeRefIntoIterator { + pub fn traverse(&self, f: &impl Fn(&T)) { + match self { + Leaf(value) => f(value), + Branch2 { left, middle, .. } => { + left.traverse(f); + middle.traverse(f); + } + Branch3 { left, middle, right, .. } => { + left.traverse(f); + middle.traverse(f); + right.traverse(f); + } + } + } + + pub fn iter(&self) -> TernaryTreeIterator { + TernaryTreeIterator { value: self, index: 0, size: self.len(), @@ -1268,10 +1283,10 @@ where T: Clone + Display + Eq + PartialEq + Debug + Ord + PartialOrd + Hash, { type Item = &'a T; - type IntoIter = TernaryTreeRefIntoIterator<'a, T>; + type IntoIter = TernaryTreeIterator<'a, T>; fn into_iter(self) -> Self::IntoIter { - TernaryTreeRefIntoIterator { + TernaryTreeIterator { value: self, index: 0, size: self.len(), @@ -1279,13 +1294,13 @@ where } } -pub struct TernaryTreeRefIntoIterator<'a, T> { +pub struct TernaryTreeIterator<'a, T> { value: &'a TernaryTree, index: usize, size: usize, } -impl<'a, T> Iterator for TernaryTreeRefIntoIterator<'a, T> +impl<'a, T> Iterator for TernaryTreeIterator<'a, T> where T: Clone + Display + Eq + PartialEq + Debug + Ord + PartialOrd + Hash, { diff --git a/tests/list_tests.rs b/tests/list_tests.rs index cb80295..64676ab 100644 --- a/tests/list_tests.rs +++ b/tests/list_tests.rs @@ -319,6 +319,27 @@ fn iterator() -> Result<(), String> { Ok(()) } +#[test] +fn traverse() -> Result<(), String> { + let origin4 = [1, 2, 3, 4]; + let data4 = TernaryTreeList::from(&origin4); + + let mut i = 0; + for _ in &data4 { + i += 1; + } + + assert_eq!(i, 4); + + i = 0; + for (idx, _) in data4.iter().enumerate() { + i += idx; + assert_eq!(data4.loop_get(idx).unwrap(), &origin4[idx]); + } + + Ok(()) +} + #[test] fn check_structure() -> Result<(), String> { let mut data = TernaryTreeList::from(&[]); From 1574bca2627ff55efc7e82681c8640d6965dbc66 Mon Sep 17 00:00:00 2001 From: tiye Date: Sun, 25 Feb 2024 22:55:46 +0800 Subject: [PATCH 2/2] expose traverse and traverse_result; tag 0.0.18 --- Cargo.toml | 2 +- benches/iterator.rs | 8 +++----- src/lib.rs | 13 +++++++++++-- src/tree.rs | 19 ++++++++++++++++++- tests/list_tests.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 77 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dfcdcdc..a5b13db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "im_ternary_tree" -version = "0.0.17" +version = "0.0.18" edition = "2021" authors = ["jiyinyiyong "] license = "MIT" diff --git a/benches/iterator.rs b/benches/iterator.rs index 8c553a3..58be576 100644 --- a/benches/iterator.rs +++ b/benches/iterator.rs @@ -1,5 +1,3 @@ -use std::cell::RefCell; - use criterion::{criterion_group, criterion_main, Criterion}; use im_ternary_tree::TernaryTreeList; @@ -24,11 +22,11 @@ fn criterion_benchmark(c: &mut Criterion) { }); c.bench_function("traverse", |b| { - let cc = RefCell::new(0); + let mut cc = 0; b.iter(|| { - data.traverse(|item| { - *cc.borrow_mut() += item; + data.traverse(&mut |item| { + cc += item; }); }) }); diff --git a/src/lib.rs b/src/lib.rs index 819a197..a1bcc46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -452,10 +452,19 @@ where } /// traverse all elements in list, use referenced value - pub fn traverse(&self, f: impl Fn(&T)) { + pub fn traverse(&self, f: &mut dyn FnMut(&T)) { match self { Empty => (), - Tree(t) => t.traverse(&f), + Tree(t) => t.traverse(f), + } + } + + /// traverse elements in list, use referenced value, + /// returns `Ok` when all elements are traversed + pub fn traverse_result(&self, f: &mut dyn FnMut(&T) -> Result<(), S>) -> Result<(), S> { + match self { + Empty => Ok(()), + Tree(t) => t.traverse_result(f), } } diff --git a/src/tree.rs b/src/tree.rs index 52fcd5a..87bc0aa 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -1240,7 +1240,7 @@ where xs } - pub fn traverse(&self, f: &impl Fn(&T)) { + pub fn traverse(&self, f: &mut dyn FnMut(&T)) { match self { Leaf(value) => f(value), Branch2 { left, middle, .. } => { @@ -1255,6 +1255,23 @@ where } } + pub fn traverse_result(&self, f: &mut dyn FnMut(&T) -> Result<(), S>) -> Result<(), S> { + match self { + Leaf(value) => f(value), + Branch2 { left, middle, .. } => { + left.traverse_result(f)?; + middle.traverse_result(f)?; + Ok(()) + } + Branch3 { left, middle, right, .. } => { + left.traverse_result(f)?; + middle.traverse_result(f)?; + right.traverse_result(f)?; + Ok(()) + } + } + } + pub fn iter(&self) -> TernaryTreeIterator { TernaryTreeIterator { value: self, diff --git a/tests/list_tests.rs b/tests/list_tests.rs index 64676ab..53c39ab 100644 --- a/tests/list_tests.rs +++ b/tests/list_tests.rs @@ -320,7 +320,7 @@ fn iterator() -> Result<(), String> { } #[test] -fn traverse() -> Result<(), String> { +fn iter_enum() -> Result<(), String> { let origin4 = [1, 2, 3, 4]; let data4 = TernaryTreeList::from(&origin4); @@ -483,3 +483,46 @@ fn split_values() -> Result<(), String> { Ok(()) } + +#[test] +fn traverse() -> Result<(), String> { + let n = 100; + let mut data = TernaryTreeList::from(&[]); + let mut total = 0; + for idx in 0..n { + data = data.append(idx); + total += idx; + } + + let mut c = 0; + + data.traverse(&mut |x| { + c += x; + }); + + assert_eq!(c, total); + + Ok(()) +} + +#[test] +fn traverse_result() -> Result<(), String> { + let n = 100; + let mut data = TernaryTreeList::from(&[]); + let mut total = 0; + for idx in 0..n { + data = data.append(idx); + total += idx; + } + + let mut c = 0; + + data.traverse_result::(&mut |x| { + c += x; + Ok(()) + })?; + + assert_eq!(c, total); + + Ok(()) +}