script/research/dark-forest: WIP implementation of a forest/tree with DFS post order traversal

This commit is contained in:
aggstam
2023-12-05 14:47:43 +02:00
parent 295c8dcff9
commit e111d1f046
4 changed files with 323 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
/target
Cargo.lock
rustfmt.toml

View File

@@ -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 <foundation@dyne.org>"]
repository = "https://github.com/darkrenaissance/darkfi"
license = "AGPL-3.0-only"
edition = "2021"
[workspace]
[dependencies]

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
use std::{collections::VecDeque, iter::FusedIterator, mem, slice::Iter};
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Debug, PartialEq)]
struct DarkLeaf<T> {
/// 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<usize>,
}
impl<T> DarkLeaf<T> {
fn new(data: T) -> DarkLeaf<T> {
Self { data, parent_index: None }
}
}
#[derive(Debug, PartialEq)]
struct DarkTree<T> {
/// This tree's leaf information, along with its data
leaf: DarkLeaf<T>,
/// Vector containing all tree's branches(children tree)
children: Vec<DarkTree<T>>,
}
impl<T> DarkTree<T> {
fn new(data: T, children: Vec<DarkTree<T>>) -> DarkTree<T> {
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<T>],
parent: Option<Box<DarkTreeIter<'a, T>>>,
}
impl<T> Default for DarkTreeIter<'_, T> {
fn default() -> Self {
DarkTreeIter { children: &[], parent: None }
}
}
impl<'a, T> Iterator for DarkTreeIter<'a, T> {
type Item = &'a DarkLeaf<T>;
fn next(&mut self) -> Option<Self::Item> {
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<T> FusedIterator for DarkTreeIter<'_, T> {}
impl<'a, T> IntoIterator for &'a DarkTree<T> {
type Item = &'a DarkLeaf<T>;
type IntoIter = DarkTreeIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
struct DarkTreeIntoIter<T> {
children: VecDeque<DarkTree<T>>,
parent: Option<Box<DarkTreeIntoIter<T>>>,
}
impl<T> Default for DarkTreeIntoIter<T> {
fn default() -> Self {
DarkTreeIntoIter { children: Default::default(), parent: None }
}
}
impl<T> Iterator for DarkTreeIntoIter<T> {
type Item = DarkLeaf<T>;
fn next(&mut self) -> Option<Self::Item> {
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<DarkTree<T>> = 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<T> FusedIterator for DarkTreeIntoIter<T> {}
impl<T> IntoIterator for DarkTree<T> {
type Item = DarkLeaf<T>;
type IntoIter = DarkTreeIntoIter<T>;
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<T>],
parent: Option<Box<DarkTreeIterMut<'a, T>>>,
parent_leaf: Option<&'a mut DarkLeaf<T>>,
}
impl<T> 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<T>;
fn next(&mut self) -> Option<Self::Item> {
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<T> {
type Item = &'a mut DarkLeaf<T>;
type IntoIter = DarkTreeIterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
#[cfg(test)]
mod tests {
use crate::DarkTree;
fn generate_tree() -> DarkTree<i32> {
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<i32> = 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![]),]),
]
)
);
}
}