mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-08 22:28:12 -05:00
script/research/dark-forest: WIP implementation of a forest/tree with DFS post order traversal
This commit is contained in:
3
script/research/dark-forest/.gitignore
vendored
Normal file
3
script/research/dark-forest/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
rustfmt.toml
|
||||
12
script/research/dark-forest/Cargo.toml
Normal file
12
script/research/dark-forest/Cargo.toml
Normal 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]
|
||||
224
script/research/dark-forest/src/lib.rs
Normal file
224
script/research/dark-forest/src/lib.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
84
script/research/dark-forest/src/tests.rs
Normal file
84
script/research/dark-forest/src/tests.rs
Normal 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![]),]),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user