diff --git a/Cargo.toml b/Cargo.toml index 0b346d6..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" @@ -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..58be576 --- /dev/null +++ b/benches/iterator.rs @@ -0,0 +1,36 @@ +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 mut cc = 0; + + b.iter(|| { + data.traverse(&mut |item| { + cc += item; + }); + }) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs index 1db71c4..a1bcc46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -451,6 +451,23 @@ where } } + /// traverse all elements in list, use referenced value + pub fn traverse(&self, f: &mut dyn FnMut(&T)) { + match self { + Empty => (), + 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), + } + } + pub fn iter(&self) -> TernaryTreeListRefIntoIterator { TernaryTreeListRefIntoIterator { value: self, diff --git a/src/tree.rs b/src/tree.rs index d809f0d..87bc0aa 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -1240,8 +1240,40 @@ where xs } - pub fn iter(&self) -> TernaryTreeRefIntoIterator { - TernaryTreeRefIntoIterator { + pub fn traverse(&self, f: &mut dyn FnMut(&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 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, index: 0, size: self.len(), @@ -1268,10 +1300,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 +1311,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..53c39ab 100644 --- a/tests/list_tests.rs +++ b/tests/list_tests.rs @@ -319,6 +319,27 @@ fn iterator() -> Result<(), String> { Ok(()) } +#[test] +fn iter_enum() -> 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(&[]); @@ -462,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(()) +}