diff --git a/script/research/dark-forest/.gitignore b/script/research/dark-forest/.gitignore new file mode 100644 index 000000000..8bc55fd23 --- /dev/null +++ b/script/research/dark-forest/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +rustfmt.toml diff --git a/script/research/dark-forest/Cargo.toml b/script/research/dark-forest/Cargo.toml new file mode 100644 index 000000000..c39b38584 --- /dev/null +++ b/script/research/dark-forest/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "dark-forest" +version = "0.1.0" +description = "Minimal Tree implementation using DFS post-order traversal to iterate its leafs." +authors = ["Dyne.org foundation "] +repository = "https://github.com/darkrenaissance/darkfi" +license = "AGPL-3.0-only" +edition = "2021" + +[workspace] + +[dependencies] diff --git a/script/research/dark-forest/src/lib.rs b/script/research/dark-forest/src/lib.rs new file mode 100644 index 000000000..1f397a461 --- /dev/null +++ b/script/research/dark-forest/src/lib.rs @@ -0,0 +1,224 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2023 Dyne.org foundation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +use std::{collections::VecDeque, iter::FusedIterator, mem, slice::Iter}; + +#[cfg(test)] +mod tests; + +#[derive(Clone, Copy, Debug, PartialEq)] +struct DarkLeaf { + /// Data holded by this leaf + data: T, + /// Index showcasing this leaf's parent tree, when all + /// leafs are in order. None indicates this leaf has no + /// parent. + parent_index: Option, +} + +impl DarkLeaf { + fn new(data: T) -> DarkLeaf { + Self { data, parent_index: None } + } +} + +#[derive(Debug, PartialEq)] +struct DarkTree { + /// This tree's leaf information, along with its data + leaf: DarkLeaf, + /// Vector containing all tree's branches(children tree) + children: Vec>, +} + +impl DarkTree { + fn new(data: T, children: Vec>) -> DarkTree { + let leaf = DarkLeaf::new(data); + Self { leaf, children } + } + + fn iter(&self) -> DarkTreeIter<'_, T> { + DarkTreeIter { children: std::slice::from_ref(self), parent: None } + } + + fn iter_mut(&mut self) -> DarkTreeIterMut<'_, T> { + DarkTreeIterMut { children: std::slice::from_mut(self), parent: None, parent_leaf: None } + } +} + +struct DarkTreeIter<'a, T> { + children: &'a [DarkTree], + parent: Option>>, +} + +impl Default for DarkTreeIter<'_, T> { + fn default() -> Self { + DarkTreeIter { children: &[], parent: None } + } +} + +impl<'a, T> Iterator for DarkTreeIter<'a, T> { + type Item = &'a DarkLeaf; + + fn next(&mut self) -> Option { + match self.children.first() { + None => match self.parent.take() { + Some(parent) => { + // Grab parent's leaf + *self = *parent; + // Its safe to unwrap here as we effectively returned + // to this tree after "pushing" it after its children + let leaf = &self.children.first().unwrap().leaf; + self.children = &self.children[1..]; + Some(leaf) + } + None => None, + }, + Some(leaf) => { + // Iterate over tree's children/sub-trees + *self = DarkTreeIter { + children: leaf.children.as_slice(), + parent: Some(Box::new(mem::take(self))), + }; + self.next() + } + } + } +} + +impl FusedIterator for DarkTreeIter<'_, T> {} + +impl<'a, T> IntoIterator for &'a DarkTree { + type Item = &'a DarkLeaf; + + type IntoIter = DarkTreeIter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +struct DarkTreeIntoIter { + children: VecDeque>, + parent: Option>>, +} + +impl Default for DarkTreeIntoIter { + fn default() -> Self { + DarkTreeIntoIter { children: Default::default(), parent: None } + } +} + +impl Iterator for DarkTreeIntoIter { + type Item = DarkLeaf; + + fn next(&mut self) -> Option { + match self.children.pop_front() { + None => match self.parent.take() { + Some(parent) => { + // Continue iteration on parent's simplings + *self = *parent; + self.next() + } + None => None, + }, + Some(mut leaf) => { + // If leaf has no children, return it + if leaf.children.is_empty() { + return Some(leaf.leaf) + } + + // Push leaf after its children + let mut children: VecDeque> = leaf.children.into(); + leaf.children = Default::default(); + children.push_back(leaf); + + // Iterate over tree's children/sub-trees + *self = DarkTreeIntoIter { children, parent: Some(Box::new(mem::take(self))) }; + self.next() + } + } + } +} + +impl FusedIterator for DarkTreeIntoIter {} + +impl IntoIterator for DarkTree { + type Item = DarkLeaf; + + type IntoIter = DarkTreeIntoIter; + + fn into_iter(self) -> Self::IntoIter { + let mut children = VecDeque::with_capacity(1); + children.push_back(self); + + DarkTreeIntoIter { children, parent: None } + } +} + +struct DarkTreeIterMut<'a, T> { + children: &'a mut [DarkTree], + parent: Option>>, + parent_leaf: Option<&'a mut DarkLeaf>, +} + +impl Default for DarkTreeIterMut<'_, T> { + fn default() -> Self { + DarkTreeIterMut { children: &mut [], parent: None, parent_leaf: None } + } +} + +impl<'a, T> Iterator for DarkTreeIterMut<'a, T> { + type Item = &'a mut DarkLeaf; + + fn next(&mut self) -> Option { + let children = mem::take(&mut self.children); + match children.split_first_mut() { + None => match self.parent.take() { + Some(parent) => { + // Grab parent's leaf + let parent_leaf = mem::take(&mut self.parent_leaf); + *self = *parent; + parent_leaf + } + None => None, + }, + Some((first, rest)) => { + // Setup simplings iteration + self.children = rest; + + // Iterate over tree's children/sub-trees + *self = DarkTreeIterMut { + children: first.children.as_mut_slice(), + parent: Some(Box::new(mem::take(self))), + parent_leaf: Some(&mut first.leaf), + }; + self.next() + } + } + } +} + +impl<'a, T> IntoIterator for &'a mut DarkTree { + type Item = &'a mut DarkLeaf; + + type IntoIter = DarkTreeIterMut<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} diff --git a/script/research/dark-forest/src/tests.rs b/script/research/dark-forest/src/tests.rs new file mode 100644 index 000000000..d991dad70 --- /dev/null +++ b/script/research/dark-forest/src/tests.rs @@ -0,0 +1,84 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2023 Dyne.org foundation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#[cfg(test)] +mod tests { + use crate::DarkTree; + + fn generate_tree() -> DarkTree { + DarkTree::new( + 5, + vec![ + DarkTree::new(4, vec![DarkTree::new(3, vec![]), DarkTree::new(2, vec![])]), + DarkTree::new(1, vec![DarkTree::new(0, vec![])]), + ], + ) + } + + #[test] + pub fn test_darktree_iterator() { + let tree = generate_tree(); + + let nums: Vec = tree.iter().map(|x| x.data).collect(); + + assert_eq!(nums, vec![3, 2, 4, 0, 1, 5]); + assert_eq!(tree.iter().nth(1).unwrap().data, 2); + } + + #[test] + fn test_owned_for_loop() { + let tree = DarkTree::new(42, vec![]); + + for leaf in tree { + let _: i32 = leaf.data; + } + } + + #[test] + fn test_borrowing_for_loop() { + let tree = DarkTree::new(42, vec![]); + + for &leaf in &tree { + let _: i32 = leaf.data; + } + } + + #[test] + fn test_darktree_mut_iterator() { + let mut tree = generate_tree(); + + for leaf in tree.iter_mut() { + leaf.data += 1; + } + + for leaf in &mut tree { + leaf.data += 1; + } + + assert_eq!( + tree, + DarkTree::new( + 7, + vec![ + DarkTree::new(6, vec![DarkTree::new(5, vec![]), DarkTree::new(4, vec![]),]), + DarkTree::new(3, vec![DarkTree::new(2, vec![]),]), + ] + ) + ); + } +}