mirror of
https://github.com/chylex/Bark-Browser.git
synced 2025-05-31 08:34:06 +02:00
Include slab-tree package sources in the repository
This commit is contained in:
parent
995e0fc8f8
commit
5f332677a7
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -311,7 +311,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "slab_tree"
|
name = "slab_tree"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "git+https://github.com/jsinger67/slab-tree.git?branch=set_root_fix#75a8dfa3b1f96f76ebe09e2e988deeffe6db54b6"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"snowflake",
|
"snowflake",
|
||||||
]
|
]
|
||||||
|
@ -21,5 +21,4 @@ slab_tree = "0.3.2"
|
|||||||
users = "0.11"
|
users = "0.11"
|
||||||
|
|
||||||
[patch.crates-io.slab_tree]
|
[patch.crates-io.slab_tree]
|
||||||
git = "https://github.com/jsinger67/slab-tree.git"
|
path = "./lib/slab-tree"
|
||||||
branch = "set_root_fix"
|
|
||||||
|
@ -42,3 +42,9 @@ Run `docker build --output out .` to build a release binary into the `out/` fold
|
|||||||
This project exists 1) because I couldn't find any tree-based file manager I liked and 2) because I wanted to have fun writing Rust, and I don't really want to spend time reading and reviewing pull requests.
|
This project exists 1) because I couldn't find any tree-based file manager I liked and 2) because I wanted to have fun writing Rust, and I don't really want to spend time reading and reviewing pull requests.
|
||||||
|
|
||||||
For now, issues are closed, and I'm not accepting any major contributions — especially ones related to the roadmap. If you have a small idea, issue, or pull request, feel free to start a [discussion](https://github.com/chylex/Bark-Browser/discussions).
|
For now, issues are closed, and I'm not accepting any major contributions — especially ones related to the roadmap. If you have a small idea, issue, or pull request, feel free to start a [discussion](https://github.com/chylex/Bark-Browser/discussions).
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
|
||||||
|
For a full list of dependencies, see [Cargo.toml](Cargo.toml).
|
||||||
|
|
||||||
|
This repository includes the sources of [slab-tree](https://github.com/iwburns/slab-tree) (by [iwburns](https://github.com/iwburns)) with a [bug fix for `set_root`](https://github.com/iwburns/slab-tree/pull/28) (by [jsinger67](https://github.com/jsinger67)) and additional modifications from me.
|
||||||
|
2
lib/slab-tree/.gitignore
vendored
Normal file
2
lib/slab-tree/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/.idea/
|
||||||
|
/target/
|
16
lib/slab-tree/Cargo.lock
generated
Normal file
16
lib/slab-tree/Cargo.lock
generated
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab_tree"
|
||||||
|
version = "0.3.2"
|
||||||
|
dependencies = [
|
||||||
|
"snowflake",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "snowflake"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1"
|
15
lib/slab-tree/Cargo.toml
Normal file
15
lib/slab-tree/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "slab_tree"
|
||||||
|
version = "0.3.2"
|
||||||
|
authors = ["Ian <iwburns8@gmail.com>"]
|
||||||
|
description = "A vec-backed tree structure with tree-specific generational indexes."
|
||||||
|
documentation = "https://docs.rs/slab_tree"
|
||||||
|
repository = "https://github.com/iwburns/slab-tree"
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = ["tree", "slab", "slab-tree"]
|
||||||
|
categories = ["data-structures"]
|
||||||
|
license = "MIT"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
snowflake = "1.3.0"
|
69
lib/slab-tree/README.md
Normal file
69
lib/slab-tree/README.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# slab_tree
|
||||||
|
|
||||||
|
[](https://travis-ci.org/iwburns/slab-tree)
|
||||||
|
[](https://github.com/iwburns/slab-tree)
|
||||||
|
|
||||||
|
A vec-backed tree structure with tree-specific generational indexes.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This library provides a `Tree<T>` struct which allows the creation and manipulation of in-memory trees.
|
||||||
|
The tree itself is backed by a vector and the tree's node relationships are managed by tree-specific
|
||||||
|
generational indexes called `NodeId`s (more below). In addition, "views" of tree nodes are handed out
|
||||||
|
which are either immutable (`NodeRef`) or mutable (`NodeMut`) instead of handing out references
|
||||||
|
directly. Most tree mutations are achieved by modifying `NodeMut`s instead of talking to the tree
|
||||||
|
itself.
|
||||||
|
|
||||||
|
`Tree`s in this crate are "just" trees. They do not allow cycles, and they do not allow arbitrary
|
||||||
|
graph structures to be created. Each node in the tree can have an arbitrary number of children, and
|
||||||
|
there is no weight associated with edges between the nodes in the tree.
|
||||||
|
|
||||||
|
**Please Note:** this crate does not support comparison-based data insertion. In other words, this is
|
||||||
|
not a binary search tree (or any other kind of search tree) crate. It is purely a crate for storing
|
||||||
|
data in a hierarchical manner. The caller must know the structure that they wish to build and then use
|
||||||
|
this crate to do so; this library will not make those structural decisions for you.
|
||||||
|
|
||||||
|
## Safety
|
||||||
|
This crate uses `#![forbid(unsafe_code)]` to prevent any and all `unsafe` code usage.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
```rust
|
||||||
|
use slab_tree::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
// "hello"
|
||||||
|
// / \
|
||||||
|
// "world" "trees"
|
||||||
|
// |
|
||||||
|
// "are"
|
||||||
|
// |
|
||||||
|
// "cool"
|
||||||
|
|
||||||
|
let mut tree = TreeBuilder::new().with_root("hello").build();
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let mut hello = tree.get_mut(root_id).unwrap();
|
||||||
|
|
||||||
|
hello.append("world");
|
||||||
|
hello
|
||||||
|
.append("trees")
|
||||||
|
.append("are")
|
||||||
|
.append("cool");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `NodeId`s
|
||||||
|
`NodeId`s are tree-specific generational indexes. Using generational indexes means that we can re-use
|
||||||
|
space inside the tree (after nodes have been removed) without also having to re-use the same tree
|
||||||
|
indexes which could potentially cause confusion and bugs. The "tree-specific" part means that indexes
|
||||||
|
from one tree cannot be confused for indexes for another tree. This is because each index contains a
|
||||||
|
process-unique-id which is shared by the tree from which that index originated.
|
||||||
|
|
||||||
|
## Project Goals
|
||||||
|
* Allow caller control of as many allocations as possible (through pre-allocation)
|
||||||
|
* Fast and Ergonomic Node insertion and removal
|
||||||
|
* Arbitrary Tree structure creation and manipulation
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
* Arbitrary _Graph_ structure creation and manipulation
|
||||||
|
* Comparison-based node insertion of any kind
|
22
lib/slab-tree/src/behaviors.rs
Normal file
22
lib/slab-tree/src/behaviors.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
///
|
||||||
|
/// Describes all the possible ways to remove a Node from a Tree.
|
||||||
|
///
|
||||||
|
pub enum RemoveBehavior {
|
||||||
|
///
|
||||||
|
/// All children of the removed Node will be dropped from the Tree. All children (and all
|
||||||
|
/// Nodes in each of their sub-trees) will no longer exist in the Tree after this operation.
|
||||||
|
///
|
||||||
|
/// This is slower than `OrphanChildren` but frees up space inside the Tree.
|
||||||
|
///
|
||||||
|
DropChildren,
|
||||||
|
|
||||||
|
///
|
||||||
|
/// All children of the removed Node will be left in the Tree (still accessible via NodeIds).
|
||||||
|
/// However, each child (and their sub-trees) will no longer be connected to the rest of the
|
||||||
|
/// Nodes in the Tree.
|
||||||
|
///
|
||||||
|
/// Orphaned nodes will live in the Tree until they are manually removed or until the Tree is
|
||||||
|
/// Dropped. This is faster than `DropChildren` but doesn't free up any space inside the Tree.
|
||||||
|
///
|
||||||
|
OrphanChildren,
|
||||||
|
}
|
136
lib/slab-tree/src/core_tree.rs
Normal file
136
lib/slab-tree/src/core_tree.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
use crate::node::Node;
|
||||||
|
use crate::slab;
|
||||||
|
use crate::NodeId;
|
||||||
|
use snowflake::ProcessUniqueId;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// A wrapper around a Slab containing Node<T> values.
|
||||||
|
///
|
||||||
|
/// Groups a collection of Node<T>s with a process unique id.
|
||||||
|
///
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub(crate) struct CoreTree<T> {
|
||||||
|
id: ProcessUniqueId,
|
||||||
|
slab: slab::Slab<Node<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> CoreTree<T> {
|
||||||
|
pub(crate) fn new(capacity: usize) -> CoreTree<T> {
|
||||||
|
CoreTree {
|
||||||
|
id: ProcessUniqueId::new(),
|
||||||
|
slab: slab::Slab::new(capacity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn capacity(&self) -> usize {
|
||||||
|
self.slab.capacity()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn insert(&mut self, data: T) -> NodeId {
|
||||||
|
let key = self.slab.insert(Node::new(data));
|
||||||
|
self.new_node_id(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remove(&mut self, node_id: NodeId) -> Option<T> {
|
||||||
|
self.filter_by_tree_id(node_id)
|
||||||
|
.and_then(|id| self.slab.remove(id.index))
|
||||||
|
.map(|node| node.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get(&self, node_id: NodeId) -> Option<&Node<T>> {
|
||||||
|
self.filter_by_tree_id(node_id)
|
||||||
|
.and_then(|id| self.slab.get(id.index))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_mut(&mut self, node_id: NodeId) -> Option<&mut Node<T>> {
|
||||||
|
self.filter_by_tree_id(node_id)
|
||||||
|
.and_then(move |id| self.slab.get_mut(id.index))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_node_id(&self, index: slab::Index) -> NodeId {
|
||||||
|
NodeId {
|
||||||
|
tree_id: self.id,
|
||||||
|
index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter_by_tree_id(&self, node_id: NodeId) -> Option<NodeId> {
|
||||||
|
if node_id.tree_id != self.id {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(node_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capacity() {
|
||||||
|
let capacity = 5;
|
||||||
|
let tree = CoreTree::<i32>::new(capacity);
|
||||||
|
assert_eq!(tree.capacity(), capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert() {
|
||||||
|
let mut tree = CoreTree::new(0);
|
||||||
|
|
||||||
|
let id = tree.insert(1);
|
||||||
|
let id2 = tree.insert(3);
|
||||||
|
|
||||||
|
assert_eq!(tree.get(id).unwrap().data, 1);
|
||||||
|
assert_eq!(tree.get(id2).unwrap().data, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove() {
|
||||||
|
let mut tree = CoreTree::new(0);
|
||||||
|
|
||||||
|
let id = tree.insert(1);
|
||||||
|
assert_eq!(tree.get(id).unwrap().data, 1);
|
||||||
|
|
||||||
|
let one = tree.remove(id);
|
||||||
|
assert!(one.is_some());
|
||||||
|
|
||||||
|
let one = one.unwrap();
|
||||||
|
assert_eq!(one, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get() {
|
||||||
|
let mut tree = CoreTree::new(0);
|
||||||
|
|
||||||
|
let id = tree.insert(1);
|
||||||
|
let id2 = tree.insert(3);
|
||||||
|
|
||||||
|
assert_eq!(tree.get(id).unwrap().data, 1);
|
||||||
|
assert_eq!(tree.get(id2).unwrap().data, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_mut() {
|
||||||
|
let mut tree = CoreTree::new(0);
|
||||||
|
|
||||||
|
let id = tree.insert(1);
|
||||||
|
let id2 = tree.insert(3);
|
||||||
|
|
||||||
|
assert_eq!(tree.get_mut(id).unwrap().data, 1);
|
||||||
|
assert_eq!(tree.get_mut(id2).unwrap().data, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_with_bad_id() {
|
||||||
|
let mut tree = CoreTree::new(0);
|
||||||
|
let tree2: CoreTree<i32> = CoreTree::new(0);
|
||||||
|
|
||||||
|
let mut id = tree.insert(1);
|
||||||
|
id.tree_id = tree2.id; // oops, wrong tree id.
|
||||||
|
|
||||||
|
let result = tree.get(id);
|
||||||
|
|
||||||
|
assert!(result.is_none());
|
||||||
|
}
|
||||||
|
}
|
223
lib/slab-tree/src/iter.rs
Normal file
223
lib/slab-tree/src/iter.rs
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
use crate::node::*;
|
||||||
|
use crate::tree::Tree;
|
||||||
|
use crate::NodeId;
|
||||||
|
|
||||||
|
// todo: document this
|
||||||
|
|
||||||
|
pub struct Ancestors<'a, T> {
|
||||||
|
node_id: Option<NodeId>,
|
||||||
|
tree: &'a Tree<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Ancestors<'a, T> {
|
||||||
|
pub(crate) fn new(node_id: Option<NodeId>, tree: &'a Tree<T>) -> Ancestors<T> {
|
||||||
|
Ancestors { node_id, tree }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for Ancestors<'a, T> {
|
||||||
|
type Item = NodeRef<'a, T>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||||
|
self.node_id
|
||||||
|
.take()
|
||||||
|
.and_then(|node_id| self.tree.get_node_relatives(node_id).parent)
|
||||||
|
.map(|id| {
|
||||||
|
self.node_id = Some(id);
|
||||||
|
NodeRef::new(id, self.tree)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// possibly re-name this, not sure how I feel about it
|
||||||
|
pub struct NextSiblings<'a, T> {
|
||||||
|
node_id: Option<NodeId>,
|
||||||
|
tree: &'a Tree<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> NextSiblings<'a, T> {
|
||||||
|
pub(crate) fn new(node_id: Option<NodeId>, tree: &'a Tree<T>) -> NextSiblings<T> {
|
||||||
|
NextSiblings { node_id, tree }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for NextSiblings<'a, T> {
|
||||||
|
type Item = NodeRef<'a, T>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||||
|
self.node_id.take().map(|node_id| {
|
||||||
|
self.node_id = self.tree.get_node_relatives(node_id).next_sibling;
|
||||||
|
NodeRef::new(node_id, self.tree)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Depth-first pre-order iterator
|
||||||
|
pub struct PreOrder<'a, T> {
|
||||||
|
start: Option<NodeRef<'a, T>>,
|
||||||
|
children: Vec<NextSiblings<'a, T>>,
|
||||||
|
tree: &'a Tree<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> PreOrder<'a, T> {
|
||||||
|
pub(crate) fn new(node: &NodeRef<'a, T>, tree: &'a Tree<T>) -> PreOrder<'a, T> {
|
||||||
|
let children = vec![];
|
||||||
|
let start = tree.get(node.node_id());
|
||||||
|
PreOrder {
|
||||||
|
start,
|
||||||
|
children,
|
||||||
|
tree,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for PreOrder<'a, T> {
|
||||||
|
type Item = NodeRef<'a, T>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||||
|
if let Some(node) = self.start.take() {
|
||||||
|
let first_child_id = node.first_child().map(|child_ref| child_ref.node_id());
|
||||||
|
self.children
|
||||||
|
.push(NextSiblings::new(first_child_id, self.tree));
|
||||||
|
Some(node)
|
||||||
|
} else {
|
||||||
|
while !self.children.is_empty() {
|
||||||
|
if let Some(node_ref) = self.children.last_mut().and_then(Iterator::next) {
|
||||||
|
if let Some(first_child) = node_ref.first_child() {
|
||||||
|
self.children
|
||||||
|
.push(NextSiblings::new(Some(first_child.node_id()), self.tree));
|
||||||
|
}
|
||||||
|
return Some(node_ref);
|
||||||
|
}
|
||||||
|
self.children.pop();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Depth-first post-order iterator
|
||||||
|
pub struct PostOrder<'a, T> {
|
||||||
|
nodes: Vec<(NodeRef<'a, T>, NextSiblings<'a, T>)>,
|
||||||
|
tree: &'a Tree<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> PostOrder<'a, T> {
|
||||||
|
pub(crate) fn new(node: &NodeRef<'a, T>, tree: &'a Tree<T>) -> PostOrder<'a, T> {
|
||||||
|
let node = tree
|
||||||
|
.get(node.node_id())
|
||||||
|
.expect("getting node of node ref id");
|
||||||
|
let first_child_id = node.first_child().map(|first_child| first_child.node_id());
|
||||||
|
let nodes = vec![(node, NextSiblings::new(first_child_id, tree))];
|
||||||
|
PostOrder { nodes, tree }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for PostOrder<'a, T> {
|
||||||
|
type Item = NodeRef<'a, T>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||||
|
if let Some((node, mut children)) = self.nodes.pop() {
|
||||||
|
if let Some(next) = children.next() {
|
||||||
|
self.nodes.push((node, children));
|
||||||
|
let mut node_id = next.node_id();
|
||||||
|
loop {
|
||||||
|
let node = self.tree.get(node_id).expect("getting node of node ref id");
|
||||||
|
if let Some(first_child) = node.first_child() {
|
||||||
|
node_id = first_child.node_id();
|
||||||
|
let mut children = NextSiblings::new(Some(node_id), self.tree);
|
||||||
|
assert!(children.next().is_some(), "skipping first child");
|
||||||
|
self.nodes.push((node, children));
|
||||||
|
} else {
|
||||||
|
break Some(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Some(node)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Depth-first level-order iterator
|
||||||
|
pub struct LevelOrder<'a, T> {
|
||||||
|
start: NodeRef<'a, T>,
|
||||||
|
levels: Vec<(NodeId, NextSiblings<'a, T>)>,
|
||||||
|
tree: &'a Tree<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> LevelOrder<'a, T> {
|
||||||
|
pub(crate) fn new(node: &NodeRef<'a, T>, tree: &'a Tree<T>) -> LevelOrder<'a, T> {
|
||||||
|
let start = tree
|
||||||
|
.get(node.node_id())
|
||||||
|
.expect("getting node of node ref id");
|
||||||
|
let levels = Vec::new();
|
||||||
|
LevelOrder {
|
||||||
|
start,
|
||||||
|
levels,
|
||||||
|
tree,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Iterator for LevelOrder<'a, T> {
|
||||||
|
type Item = NodeRef<'a, T>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<NodeRef<'a, T>> {
|
||||||
|
if self.levels.is_empty() {
|
||||||
|
let first_child_id = self.start.first_child().map(|child| child.node_id());
|
||||||
|
self.levels.push((
|
||||||
|
self.start.node_id(),
|
||||||
|
NextSiblings::new(first_child_id, self.tree),
|
||||||
|
));
|
||||||
|
let node = self
|
||||||
|
.tree
|
||||||
|
.get(self.start.node_id())
|
||||||
|
.expect("getting node of existing node ref id");
|
||||||
|
Some(node)
|
||||||
|
} else {
|
||||||
|
let mut on_level = self.levels.len();
|
||||||
|
let next_level = on_level + 1;
|
||||||
|
let mut level = on_level;
|
||||||
|
while level > 0 {
|
||||||
|
if let Some(node) = self.levels.last_mut().expect("non-empty levels").1.next() {
|
||||||
|
if level >= on_level {
|
||||||
|
return Some(node);
|
||||||
|
} else {
|
||||||
|
let first_child_id = node.first_child().map(|child| child.node_id());
|
||||||
|
self.levels
|
||||||
|
.push((node.node_id(), NextSiblings::new(first_child_id, self.tree)));
|
||||||
|
level += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (node_id, _) = self.levels.pop().expect("on level > 0");
|
||||||
|
if let Some(next) = self.levels.last_mut().and_then(|level| level.1.next()) {
|
||||||
|
let first_child_id = next.first_child().map(|child| child.node_id());
|
||||||
|
self.levels
|
||||||
|
.push((next.node_id(), NextSiblings::new(first_child_id, self.tree)));
|
||||||
|
} else if level == 1 {
|
||||||
|
if on_level < next_level {
|
||||||
|
on_level += 1;
|
||||||
|
let node = self
|
||||||
|
.tree
|
||||||
|
.get(node_id)
|
||||||
|
.expect("getting node of existing node ref id");
|
||||||
|
let first_child_id = node.first_child().map(|child| child.node_id());
|
||||||
|
self.levels.push((
|
||||||
|
node.node_id(),
|
||||||
|
NextSiblings::new(first_child_id, self.tree),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
level -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
lib/slab-tree/src/lib.rs
Normal file
96
lib/slab-tree/src/lib.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
//!
|
||||||
|
//! # slab_tree
|
||||||
|
//!
|
||||||
|
//! [](https://travis-ci.org/iwburns/slab-tree)
|
||||||
|
//! [](https://github.com/iwburns/slab-tree)
|
||||||
|
//!
|
||||||
|
//! A vec-backed tree structure with tree-specific generational indexes.
|
||||||
|
//!
|
||||||
|
//! ## Overview
|
||||||
|
//!
|
||||||
|
//! This library provides a `Tree<T>` struct which allows the creation and manipulation of in-memory trees.
|
||||||
|
//! The tree itself is backed by a vector and the tree's node relationships are managed by tree-specific
|
||||||
|
//! generational indexes called `NodeId`s (more below). In addition, "views" of tree nodes are handed out
|
||||||
|
//! which are either immutable (`NodeRef`) or mutable (`NodeMut`) instead of handing out references
|
||||||
|
//! directly. Most tree mutations are achieved by modifying `NodeMut`s instead of talking to the tree
|
||||||
|
//! itself.
|
||||||
|
//!
|
||||||
|
//! `Tree`s in this crate are "just" trees. They do not allow cycles, and they do not allow arbitrary
|
||||||
|
//! graph structures to be created. Each node in the tree can have an arbitrary number of children, and
|
||||||
|
//! there is no weight associated with edges between the nodes in the tree.
|
||||||
|
//!
|
||||||
|
//! **Please Note:** this crate does not support comparison-based data insertion. In other words, this is
|
||||||
|
//! not a binary search tree (or any other kind of search tree) crate. It is purely a crate for storing
|
||||||
|
//! data in a hierarchical manner. The caller must know the structure that they wish to build and then use
|
||||||
|
//! this crate to do so; this library will not make those structural decisions for you.
|
||||||
|
//!
|
||||||
|
//! ## Safety
|
||||||
|
//! This crate uses `#![forbid(unsafe_code)]` to prevent any and all `unsafe` code usage.
|
||||||
|
//!
|
||||||
|
//! ## Example Usage
|
||||||
|
//! ```
|
||||||
|
//! use slab_tree::*;
|
||||||
|
//!
|
||||||
|
//! // "hello"
|
||||||
|
//! // / \
|
||||||
|
//! // "world" "trees"
|
||||||
|
//! // |
|
||||||
|
//! // "are"
|
||||||
|
//! // |
|
||||||
|
//! // "cool"
|
||||||
|
//!
|
||||||
|
//! let mut tree = TreeBuilder::new().with_root("hello").build();
|
||||||
|
//! let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
//! let mut hello = tree.get_mut(root_id).unwrap();
|
||||||
|
//!
|
||||||
|
//! hello.append("world");
|
||||||
|
//! hello
|
||||||
|
//! .append("trees")
|
||||||
|
//! .append("are")
|
||||||
|
//! .append("cool");
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## `NodeId`s
|
||||||
|
//! `NodeId`s are tree-specific generational indexes. Using generational indexes means that we can re-use
|
||||||
|
//! space inside the tree (after nodes have been removed) without also having to re-use the same tree
|
||||||
|
//! indexes which could potentially cause confusion and bugs. The "tree-specific" part means that indexes
|
||||||
|
//! from one tree cannot be confused for indexes for another tree. This is because each index contains a
|
||||||
|
//! process-unique-id which is shared by the tree from which that index originated.
|
||||||
|
//!
|
||||||
|
//! ## Project Goals
|
||||||
|
//! * Allow caller control of as many allocations as possible (through pre-allocation)
|
||||||
|
//! * Fast and Ergonomic Node insertion and removal
|
||||||
|
//! * Arbitrary Tree structure creation and manipulation
|
||||||
|
//!
|
||||||
|
//! ## Non-Goals
|
||||||
|
//! * Arbitrary _Graph_ structure creation and manipulation
|
||||||
|
//! * Comparison-based node insertion of any kind
|
||||||
|
//!
|
||||||
|
|
||||||
|
pub mod behaviors;
|
||||||
|
mod core_tree;
|
||||||
|
pub mod iter;
|
||||||
|
pub mod node;
|
||||||
|
mod slab;
|
||||||
|
pub mod tree;
|
||||||
|
|
||||||
|
pub use crate::behaviors::RemoveBehavior;
|
||||||
|
pub use crate::iter::Ancestors;
|
||||||
|
pub use crate::iter::NextSiblings;
|
||||||
|
pub use crate::node::NodeMut;
|
||||||
|
pub use crate::node::NodeRef;
|
||||||
|
pub use crate::tree::Tree;
|
||||||
|
pub use crate::tree::TreeBuilder;
|
||||||
|
use snowflake::ProcessUniqueId;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// An identifier used to differentiate between Nodes and tie
|
||||||
|
/// them to a specific tree.
|
||||||
|
///
|
||||||
|
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||||
|
pub struct NodeId {
|
||||||
|
tree_id: ProcessUniqueId,
|
||||||
|
index: slab::Index,
|
||||||
|
}
|
37
lib/slab-tree/src/node.rs
Normal file
37
lib/slab-tree/src/node.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
mod node_mut;
|
||||||
|
mod node_ref;
|
||||||
|
|
||||||
|
pub use self::node_mut::NodeMut;
|
||||||
|
pub use self::node_ref::NodeRef;
|
||||||
|
|
||||||
|
use crate::NodeId;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub(crate) struct Relatives {
|
||||||
|
pub(crate) parent: Option<NodeId>,
|
||||||
|
pub(crate) prev_sibling: Option<NodeId>,
|
||||||
|
pub(crate) next_sibling: Option<NodeId>,
|
||||||
|
pub(crate) first_child: Option<NodeId>,
|
||||||
|
pub(crate) last_child: Option<NodeId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub(crate) struct Node<T> {
|
||||||
|
pub(crate) data: T,
|
||||||
|
pub(crate) relatives: Relatives,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Node<T> {
|
||||||
|
pub(crate) fn new(data: T) -> Node<T> {
|
||||||
|
Node {
|
||||||
|
data,
|
||||||
|
relatives: Relatives {
|
||||||
|
parent: None,
|
||||||
|
prev_sibling: None,
|
||||||
|
next_sibling: None,
|
||||||
|
first_child: None,
|
||||||
|
last_child: None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1399
lib/slab-tree/src/node/node_mut.rs
Normal file
1399
lib/slab-tree/src/node/node_mut.rs
Normal file
File diff suppressed because it is too large
Load Diff
381
lib/slab-tree/src/node/node_ref.rs
Normal file
381
lib/slab-tree/src/node/node_ref.rs
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
use crate::iter::Ancestors;
|
||||||
|
use crate::iter::LevelOrder;
|
||||||
|
use crate::iter::NextSiblings;
|
||||||
|
use crate::iter::PostOrder;
|
||||||
|
use crate::iter::PreOrder;
|
||||||
|
use crate::node::Node;
|
||||||
|
use crate::tree::Tree;
|
||||||
|
use crate::NodeId;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// An immutable reference to a given `Node`'s data and its relatives.
|
||||||
|
///
|
||||||
|
pub struct NodeRef<'a, T> {
|
||||||
|
node_id: NodeId,
|
||||||
|
tree: &'a Tree<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> NodeRef<'a, T> {
|
||||||
|
pub(crate) fn new(node_id: NodeId, tree: &'a Tree<T>) -> NodeRef<T> {
|
||||||
|
NodeRef { node_id, tree }
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the `NodeId` that identifies this `Node` in the tree.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
/// let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
/// let root = tree.root_mut().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// let root_id_again = root.as_ref().node_id();
|
||||||
|
///
|
||||||
|
/// assert_eq!(root_id_again, root_id);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn node_id(&self) -> NodeId {
|
||||||
|
self.node_id
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a reference to the data contained by the given `Node`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
///
|
||||||
|
/// let root = tree.root().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// assert_eq!(root.data(), &1);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn data(&self) -> &'a T {
|
||||||
|
if let Some(node) = self.tree.get_node(self.node_id) {
|
||||||
|
&node.data
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `NodeRef` pointing to this `Node`'s parent. Returns a `Some`-value containing
|
||||||
|
/// the `NodeRef` if this `Node` has a parent; otherwise returns a `None`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
///
|
||||||
|
/// let root = tree.root().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// assert!(root.parent().is_none());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn parent(&self) -> Option<NodeRef<T>> {
|
||||||
|
self.get_self_as_node()
|
||||||
|
.relatives
|
||||||
|
.parent
|
||||||
|
.map(|id| NodeRef::new(id, self.tree))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `NodeRef` pointing to this `Node`'s previous sibling. Returns a `Some`-value
|
||||||
|
/// containing the `NodeRef` if this `Node` has a previous sibling; otherwise returns a `None`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
///
|
||||||
|
/// let root = tree.root().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// assert!(root.prev_sibling().is_none());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn prev_sibling(&self) -> Option<NodeRef<T>> {
|
||||||
|
self.get_self_as_node()
|
||||||
|
.relatives
|
||||||
|
.prev_sibling
|
||||||
|
.map(|id| NodeRef::new(id, self.tree))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `NodeRef` pointing to this `Node`'s next sibling. Returns a `Some`-value
|
||||||
|
/// containing the `NodeRef` if this `Node` has a next sibling; otherwise returns a `None`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
///
|
||||||
|
/// let root = tree.root().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// assert!(root.next_sibling().is_none());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn next_sibling(&self) -> Option<NodeRef<T>> {
|
||||||
|
self.get_self_as_node()
|
||||||
|
.relatives
|
||||||
|
.next_sibling
|
||||||
|
.map(|id| NodeRef::new(id, self.tree))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `NodeRef` pointing to this `Node`'s first child. Returns a `Some`-value
|
||||||
|
/// containing the `NodeRef` if this `Node` has a first child; otherwise returns a `None`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
///
|
||||||
|
/// let root = tree.root().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// assert!(root.first_child().is_none());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn first_child(&self) -> Option<NodeRef<T>> {
|
||||||
|
self.get_self_as_node()
|
||||||
|
.relatives
|
||||||
|
.first_child
|
||||||
|
.map(|id| NodeRef::new(id, self.tree))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `NodeRef` pointing to this `Node`'s last child. Returns a `Some`-value
|
||||||
|
/// containing the `NodeRef` if this `Node` has a last child; otherwise returns a `None`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
///
|
||||||
|
/// let root = tree.root().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// assert!(root.last_child().is_none());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn last_child(&self) -> Option<NodeRef<T>> {
|
||||||
|
self.get_self_as_node()
|
||||||
|
.relatives
|
||||||
|
.last_child
|
||||||
|
.map(|id| NodeRef::new(id, self.tree))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `Iterator` over the given `Node`'s ancestors. Each call to `Iterator::next()`
|
||||||
|
/// returns a `NodeRef` pointing to the current `Node`'s parent.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
///
|
||||||
|
/// let leaf_id = tree.root_mut().expect("root doesn't exist?")
|
||||||
|
/// .append(2)
|
||||||
|
/// .append(3)
|
||||||
|
/// .append(4)
|
||||||
|
/// .node_id();
|
||||||
|
///
|
||||||
|
/// let leaf = tree.get(leaf_id).unwrap();
|
||||||
|
///
|
||||||
|
/// let values = [3, 2, 1];
|
||||||
|
/// for (i, ancestor) in leaf.ancestors().enumerate() {
|
||||||
|
/// assert_eq!(ancestor.data(), &values[i]);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn ancestors(&self) -> Ancestors<'a, T> {
|
||||||
|
Ancestors::new(Some(self.node_id), self.tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `Iterator` over the given `Node`'s children. Each call to `Iterator::next()`
|
||||||
|
/// returns a `NodeRef` pointing to the next child of the given `Node`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
///
|
||||||
|
/// let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||||
|
/// root.append(2);
|
||||||
|
/// root.append(3);
|
||||||
|
/// root.append(4);
|
||||||
|
///
|
||||||
|
/// let root = root.as_ref();
|
||||||
|
///
|
||||||
|
/// let values = [2, 3, 4];
|
||||||
|
/// for (i, child) in root.children().enumerate() {
|
||||||
|
/// assert_eq!(child.data(), &values[i]);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn children(&self) -> NextSiblings<'a, T> {
|
||||||
|
let first_child_id = self.tree.get_node_relatives(self.node_id).first_child;
|
||||||
|
NextSiblings::new(first_child_id, self.tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Depth-first pre-order traversal.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(0i64).build();
|
||||||
|
/// let root_id = tree.root().unwrap().node_id();
|
||||||
|
/// let one_id = tree.get_mut(root_id).unwrap().append(1).node_id();
|
||||||
|
/// tree.get_mut(one_id).unwrap().append(2);
|
||||||
|
/// tree.get_mut(one_id).unwrap().append(3);
|
||||||
|
/// tree.get_mut(root_id).unwrap().append(4);
|
||||||
|
/// let pre_order = tree.root().unwrap().traverse_pre_order()
|
||||||
|
/// .map(|node_ref| node_ref.data().clone()).collect::<Vec<i64>>();
|
||||||
|
/// assert_eq!(pre_order, vec![0, 1, 2, 3, 4]);
|
||||||
|
/// ```
|
||||||
|
pub fn traverse_pre_order(&self) -> PreOrder<'a, T> {
|
||||||
|
PreOrder::new(self, self.tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Depth-first post-order traversal.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(0i64).build();
|
||||||
|
/// let root_id = tree.root().unwrap().node_id();
|
||||||
|
/// let one_id = tree.get_mut(root_id).unwrap().append(1).node_id();
|
||||||
|
/// tree.get_mut(one_id).unwrap().append(2);
|
||||||
|
/// tree.get_mut(one_id).unwrap().append(3);
|
||||||
|
/// tree.get_mut(root_id).unwrap().append(4);
|
||||||
|
/// let post_order = tree.root().unwrap().traverse_post_order()
|
||||||
|
/// .map(|node_ref| node_ref.data().clone()).collect::<Vec<i64>>();
|
||||||
|
/// assert_eq!(post_order, vec![2, 3, 1, 4, 0]);
|
||||||
|
/// ```
|
||||||
|
pub fn traverse_post_order(&self) -> PostOrder<'a, T> {
|
||||||
|
PostOrder::new(self, self.tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Depth-first level-order traversal.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(0i64).build();
|
||||||
|
/// let root_id = tree.root().unwrap().node_id();
|
||||||
|
/// let one_id = tree.get_mut(root_id).unwrap().append(1).node_id();
|
||||||
|
/// tree.get_mut(one_id).unwrap().append(2);
|
||||||
|
/// tree.get_mut(one_id).unwrap().append(3);
|
||||||
|
/// tree.get_mut(root_id).unwrap().append(4);
|
||||||
|
/// let level_order = tree.root().unwrap().traverse_level_order()
|
||||||
|
/// .map(|node_ref| node_ref.data().clone()).collect::<Vec<i64>>();
|
||||||
|
/// assert_eq!(level_order, vec![0, 1, 4, 2, 3]);
|
||||||
|
/// ```
|
||||||
|
pub fn traverse_level_order(&self) -> LevelOrder<'a, T> {
|
||||||
|
LevelOrder::new(self, self.tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_self_as_node(&self) -> &Node<T> {
|
||||||
|
if let Some(node) = self.tree.get_node(self.node_id) {
|
||||||
|
&node
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod node_ref_tests {
|
||||||
|
use crate::tree::Tree;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn data() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
tree.set_root(1);
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root_ref = tree.get(root_id).unwrap();
|
||||||
|
assert_eq!(root_ref.data(), &1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parent() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
tree.set_root(1);
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root_ref = tree.get(root_id).unwrap();
|
||||||
|
assert!(root_ref.parent().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn prev_sibling() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
tree.set_root(1);
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root_ref = tree.get(root_id).unwrap();
|
||||||
|
assert!(root_ref.prev_sibling().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn next_sibling() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
tree.set_root(1);
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root_ref = tree.get(root_id).unwrap();
|
||||||
|
assert!(root_ref.next_sibling().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_child() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
tree.set_root(1);
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root_ref = tree.get(root_id).unwrap();
|
||||||
|
assert!(root_ref.first_child().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn last_child() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
tree.set_root(1);
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root_ref = tree.get(root_id).unwrap();
|
||||||
|
assert!(root_ref.last_child().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ancestors() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
tree.set_root(1);
|
||||||
|
|
||||||
|
let mut root_mut = tree.root_mut().expect("root doesn't exist");
|
||||||
|
let node_id = root_mut.append(2).append(3).append(4).append(5).node_id();
|
||||||
|
|
||||||
|
let values = [4, 3, 2, 1];
|
||||||
|
|
||||||
|
let bottom_node = tree.get(node_id).unwrap();
|
||||||
|
for (i, node_ref) in bottom_node.ancestors().enumerate() {
|
||||||
|
assert_eq!(node_ref.data(), &values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn children() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
tree.set_root(1);
|
||||||
|
|
||||||
|
let mut root = tree.root_mut().expect("root doesn't exist");
|
||||||
|
root.append(2);
|
||||||
|
root.append(3);
|
||||||
|
root.append(4);
|
||||||
|
root.append(5);
|
||||||
|
|
||||||
|
let values = [2, 3, 4, 5];
|
||||||
|
let root = root.as_ref();
|
||||||
|
|
||||||
|
for (i, node_ref) in root.children().enumerate() {
|
||||||
|
assert_eq!(node_ref.data(), &values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
497
lib/slab-tree/src/slab.rs
Normal file
497
lib/slab-tree/src/slab.rs
Normal file
@ -0,0 +1,497 @@
|
|||||||
|
use std::mem;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||||
|
pub(super) struct Index {
|
||||||
|
index: usize,
|
||||||
|
generation: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum Slot<T> {
|
||||||
|
Empty { next_free_slot: Option<usize> },
|
||||||
|
Filled { item: T, generation: u64 },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub(super) struct Slab<T> {
|
||||||
|
data: Vec<Slot<T>>,
|
||||||
|
first_free_slot: Option<usize>,
|
||||||
|
generation: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Slab<T> {
|
||||||
|
pub(super) fn new(capacity: usize) -> Slab<T> {
|
||||||
|
Slab {
|
||||||
|
data: Vec::with_capacity(capacity),
|
||||||
|
first_free_slot: None,
|
||||||
|
generation: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn capacity(&self) -> usize {
|
||||||
|
self.data.capacity()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn insert(&mut self, item: T) -> Index {
|
||||||
|
let new_slot = Slot::Filled {
|
||||||
|
item,
|
||||||
|
generation: self.generation,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(index) = self.first_free_slot {
|
||||||
|
match mem::replace(&mut self.data[index], new_slot) {
|
||||||
|
Slot::Empty { next_free_slot } => {
|
||||||
|
self.first_free_slot = next_free_slot;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Index {
|
||||||
|
index,
|
||||||
|
generation: self.generation,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.data.push(new_slot);
|
||||||
|
Index {
|
||||||
|
index: self.data.len() - 1,
|
||||||
|
generation: self.generation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn remove(&mut self, index: Index) -> Option<T> {
|
||||||
|
if index.index >= self.data.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let slot = mem::replace(
|
||||||
|
&mut self.data[index.index],
|
||||||
|
Slot::Empty {
|
||||||
|
next_free_slot: self.first_free_slot,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
match slot {
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
if index.generation == generation {
|
||||||
|
self.generation += 1;
|
||||||
|
self.first_free_slot = Some(index.index);
|
||||||
|
Some(item)
|
||||||
|
} else {
|
||||||
|
self.data[index.index] = Slot::Filled { item, generation };
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s => {
|
||||||
|
self.data[index.index] = s;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn get(&self, index: Index) -> Option<&T> {
|
||||||
|
self.data.get(index.index).and_then(|slot| match slot {
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
if index.generation == *generation {
|
||||||
|
return Some(item);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_mut(&mut self, index: Index) -> Option<&mut T> {
|
||||||
|
self.data.get_mut(index.index).and_then(|slot| match slot {
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
if index.generation == *generation {
|
||||||
|
return Some(item);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capacity() {
|
||||||
|
let capacity = 5;
|
||||||
|
let slab = Slab::<i32>::new(capacity);
|
||||||
|
|
||||||
|
assert_eq!(slab.capacity(), capacity);
|
||||||
|
assert!(slab.first_free_slot.is_none());
|
||||||
|
assert_eq!(slab.generation, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert() {
|
||||||
|
let capacity = 2;
|
||||||
|
let mut slab = Slab::new(capacity);
|
||||||
|
|
||||||
|
let six = slab.insert(6);
|
||||||
|
|
||||||
|
assert!(slab.first_free_slot.is_none());
|
||||||
|
assert_eq!(slab.generation, 0);
|
||||||
|
assert_eq!(slab.data.len(), 1);
|
||||||
|
assert_eq!(slab.data.capacity(), capacity);
|
||||||
|
|
||||||
|
assert_eq!(six.generation, 0);
|
||||||
|
assert_eq!(six.index, 0);
|
||||||
|
|
||||||
|
let seven = slab.insert(7);
|
||||||
|
|
||||||
|
assert!(slab.first_free_slot.is_none());
|
||||||
|
assert_eq!(slab.generation, 0);
|
||||||
|
assert_eq!(slab.data.len(), 2);
|
||||||
|
assert_eq!(slab.data.capacity(), capacity);
|
||||||
|
|
||||||
|
assert_eq!(seven.generation, 0);
|
||||||
|
assert_eq!(seven.index, 1);
|
||||||
|
|
||||||
|
let eight = slab.insert(8);
|
||||||
|
|
||||||
|
assert!(slab.first_free_slot.is_none());
|
||||||
|
assert_eq!(slab.generation, 0);
|
||||||
|
assert_eq!(slab.data.len(), 3);
|
||||||
|
assert!(slab.data.capacity() >= capacity);
|
||||||
|
|
||||||
|
assert_eq!(eight.generation, 0);
|
||||||
|
assert_eq!(eight.index, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_basic() {
|
||||||
|
let mut slab = Slab::new(5);
|
||||||
|
let _six = slab.insert(6);
|
||||||
|
let seven = slab.insert(7);
|
||||||
|
let _eight = slab.insert(8);
|
||||||
|
// |6|7|8|
|
||||||
|
|
||||||
|
let seven_rem = slab.remove(seven);
|
||||||
|
// |6|.|8|
|
||||||
|
assert!(seven_rem.is_some());
|
||||||
|
assert_eq!(seven_rem.unwrap(), 7);
|
||||||
|
|
||||||
|
assert_eq!(slab.first_free_slot.unwrap_or(10), 1);
|
||||||
|
assert_eq!(slab.generation, 1);
|
||||||
|
|
||||||
|
let six_slot = slab.data.get(0);
|
||||||
|
assert!(six_slot.is_some());
|
||||||
|
|
||||||
|
match six_slot.unwrap() {
|
||||||
|
Slot::Empty { .. } => {
|
||||||
|
panic!("Slot should be filled after call to insert.");
|
||||||
|
}
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
assert_eq!(item, &6);
|
||||||
|
assert_eq!(generation, &0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let seven_slot = slab.data.get(1);
|
||||||
|
assert!(seven_slot.is_some());
|
||||||
|
|
||||||
|
match seven_slot.unwrap() {
|
||||||
|
Slot::Empty { next_free_slot } => {
|
||||||
|
assert!(next_free_slot.is_none());
|
||||||
|
}
|
||||||
|
Slot::Filled { .. } => {
|
||||||
|
panic!("Slot should be empty after call to remove.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let eight_slot = slab.data.get(2);
|
||||||
|
assert!(eight_slot.is_some());
|
||||||
|
|
||||||
|
match eight_slot.unwrap() {
|
||||||
|
Slot::Empty { .. } => {
|
||||||
|
panic!("Slot should be filled after call to insert.");
|
||||||
|
}
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
assert_eq!(item, &8);
|
||||||
|
assert_eq!(generation, &0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn double_remove() {
|
||||||
|
let mut slab = Slab::new(5);
|
||||||
|
let _six = slab.insert(6);
|
||||||
|
let seven = slab.insert(7);
|
||||||
|
let _eight = slab.insert(8);
|
||||||
|
// |6|7|8|
|
||||||
|
|
||||||
|
let seven_rem = slab.remove(seven);
|
||||||
|
// |6|.|8|
|
||||||
|
assert!(seven_rem.is_some());
|
||||||
|
assert_eq!(seven_rem.unwrap(), 7);
|
||||||
|
|
||||||
|
let seven_again = slab.remove(seven);
|
||||||
|
assert!(seven_again.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_multiple() {
|
||||||
|
let mut slab = Slab::new(5);
|
||||||
|
let _six = slab.insert(6);
|
||||||
|
let seven = slab.insert(7);
|
||||||
|
let eight = slab.insert(8);
|
||||||
|
// |6|7|8|
|
||||||
|
|
||||||
|
let seven_rem = slab.remove(seven);
|
||||||
|
// |6|.|8|
|
||||||
|
assert!(seven_rem.is_some());
|
||||||
|
assert_eq!(seven_rem.unwrap(), 7);
|
||||||
|
|
||||||
|
assert_eq!(slab.first_free_slot.unwrap_or(10), 1);
|
||||||
|
assert_eq!(slab.generation, 1);
|
||||||
|
|
||||||
|
let six_slot = slab.data.get(0);
|
||||||
|
assert!(six_slot.is_some());
|
||||||
|
|
||||||
|
match six_slot.unwrap() {
|
||||||
|
Slot::Empty { .. } => {
|
||||||
|
panic!("Slot should be filled after call to insert.");
|
||||||
|
}
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
assert_eq!(item, &6);
|
||||||
|
assert_eq!(generation, &0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let seven_slot = slab.data.get(1);
|
||||||
|
assert!(seven_slot.is_some());
|
||||||
|
|
||||||
|
match seven_slot.unwrap() {
|
||||||
|
Slot::Empty { next_free_slot } => {
|
||||||
|
assert!(next_free_slot.is_none());
|
||||||
|
}
|
||||||
|
Slot::Filled { .. } => {
|
||||||
|
panic!("Slot should be empty after call to remove.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let eight_slot = slab.data.get(2);
|
||||||
|
assert!(eight_slot.is_some());
|
||||||
|
|
||||||
|
match eight_slot.unwrap() {
|
||||||
|
Slot::Empty { .. } => {
|
||||||
|
panic!("Slot should be filled after call to insert.");
|
||||||
|
}
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
assert_eq!(item, &8);
|
||||||
|
assert_eq!(generation, &0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let eight_rem = slab.remove(eight);
|
||||||
|
// |6|.|.|
|
||||||
|
assert!(eight_rem.is_some());
|
||||||
|
assert_eq!(eight_rem.unwrap(), 8);
|
||||||
|
|
||||||
|
assert_eq!(slab.first_free_slot.unwrap_or(10), 2);
|
||||||
|
assert_eq!(slab.generation, 2);
|
||||||
|
|
||||||
|
let six_slot = slab.data.get(0);
|
||||||
|
assert!(six_slot.is_some());
|
||||||
|
|
||||||
|
match six_slot.unwrap() {
|
||||||
|
Slot::Empty { .. } => {
|
||||||
|
panic!("Slot should be filled after call to insert.");
|
||||||
|
}
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
assert_eq!(item, &6);
|
||||||
|
assert_eq!(generation, &0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let seven_slot = slab.data.get(1);
|
||||||
|
assert!(seven_slot.is_some());
|
||||||
|
|
||||||
|
match seven_slot.unwrap() {
|
||||||
|
Slot::Empty { next_free_slot } => {
|
||||||
|
assert!(next_free_slot.is_none());
|
||||||
|
}
|
||||||
|
Slot::Filled { .. } => {
|
||||||
|
panic!("Slot should be empty after call to remove.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let eight_slot = slab.data.get(2);
|
||||||
|
assert!(eight_slot.is_some());
|
||||||
|
|
||||||
|
match eight_slot.unwrap() {
|
||||||
|
Slot::Empty { next_free_slot } => {
|
||||||
|
assert!(next_free_slot.is_some());
|
||||||
|
assert_eq!(next_free_slot.unwrap(), 1);
|
||||||
|
}
|
||||||
|
Slot::Filled { .. } => {
|
||||||
|
panic!("Slot should be empty after call to remove.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_and_reinsert() {
|
||||||
|
let mut slab = Slab::new(5);
|
||||||
|
let _six = slab.insert(6);
|
||||||
|
let seven = slab.insert(7);
|
||||||
|
let eight = slab.insert(8);
|
||||||
|
// |6|7|8|
|
||||||
|
|
||||||
|
let seven_rem = slab.remove(seven);
|
||||||
|
// |6|.|8|
|
||||||
|
assert!(seven_rem.is_some());
|
||||||
|
assert_eq!(seven_rem.unwrap(), 7);
|
||||||
|
|
||||||
|
assert_eq!(slab.first_free_slot.unwrap_or(10), 1);
|
||||||
|
assert_eq!(slab.generation, 1);
|
||||||
|
|
||||||
|
let eight_rem = slab.remove(eight);
|
||||||
|
// |6|.|.|
|
||||||
|
assert!(eight_rem.is_some());
|
||||||
|
assert_eq!(eight_rem.unwrap(), 8);
|
||||||
|
|
||||||
|
assert_eq!(slab.first_free_slot.unwrap_or(10), 2);
|
||||||
|
assert_eq!(slab.generation, 2);
|
||||||
|
|
||||||
|
let nine = slab.insert(9);
|
||||||
|
// |6|.|9|
|
||||||
|
assert_eq!(nine.index, 2);
|
||||||
|
assert_eq!(nine.generation, 2);
|
||||||
|
|
||||||
|
let eight_again = slab.remove(eight);
|
||||||
|
assert!(eight_again.is_none());
|
||||||
|
|
||||||
|
let six_slot = slab.data.get(0);
|
||||||
|
assert!(six_slot.is_some());
|
||||||
|
|
||||||
|
match six_slot.unwrap() {
|
||||||
|
Slot::Empty { .. } => {
|
||||||
|
panic!("Slot should be filled after call to insert.");
|
||||||
|
}
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
assert_eq!(item, &6);
|
||||||
|
assert_eq!(generation, &0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let seven_slot = slab.data.get(1);
|
||||||
|
assert!(seven_slot.is_some());
|
||||||
|
|
||||||
|
match seven_slot.unwrap() {
|
||||||
|
Slot::Empty { next_free_slot } => {
|
||||||
|
assert!(next_free_slot.is_none());
|
||||||
|
}
|
||||||
|
Slot::Filled { .. } => {
|
||||||
|
panic!("Slot should be empty after call to remove.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let nine_slot = slab.data.get(2);
|
||||||
|
assert!(nine_slot.is_some());
|
||||||
|
|
||||||
|
match nine_slot.unwrap() {
|
||||||
|
Slot::Empty { .. } => {
|
||||||
|
panic!("Slot should be filled after call to insert.");
|
||||||
|
}
|
||||||
|
Slot::Filled { item, generation } => {
|
||||||
|
assert_eq!(item, &9);
|
||||||
|
assert_eq!(generation, &2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_with_bad_index() {
|
||||||
|
let mut slab = Slab::new(5);
|
||||||
|
let _six = slab.insert(6);
|
||||||
|
let _seven = slab.insert(7);
|
||||||
|
let mut eight = slab.insert(8);
|
||||||
|
// |0|1|2| index
|
||||||
|
// |6|7|8| value
|
||||||
|
|
||||||
|
eight.index = 3; // oops, this should be 2
|
||||||
|
|
||||||
|
let eight_rem = slab.remove(eight);
|
||||||
|
assert!(eight_rem.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get() {
|
||||||
|
let mut slab = Slab::new(5);
|
||||||
|
|
||||||
|
let six = slab.insert(6);
|
||||||
|
assert_eq!(six.index, 0);
|
||||||
|
assert_eq!(six.generation, 0);
|
||||||
|
|
||||||
|
let seven = slab.insert(7);
|
||||||
|
assert_eq!(seven.index, 1);
|
||||||
|
assert_eq!(seven.generation, 0);
|
||||||
|
|
||||||
|
let six_ref = slab.get(six);
|
||||||
|
assert!(six_ref.is_some());
|
||||||
|
assert_eq!(six_ref.unwrap(), &6);
|
||||||
|
|
||||||
|
slab.remove(six);
|
||||||
|
|
||||||
|
let six_ref = slab.get(six);
|
||||||
|
assert!(six_ref.is_none());
|
||||||
|
|
||||||
|
let eight = slab.insert(8);
|
||||||
|
assert_eq!(eight.index, 0);
|
||||||
|
assert_eq!(eight.generation, 1);
|
||||||
|
|
||||||
|
let eight_ref = slab.get(eight);
|
||||||
|
assert!(eight_ref.is_some());
|
||||||
|
assert_eq!(eight_ref.unwrap(), &8);
|
||||||
|
|
||||||
|
let six_ref = slab.get(six);
|
||||||
|
assert!(six_ref.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_mut() {
|
||||||
|
let mut slab = Slab::new(5);
|
||||||
|
|
||||||
|
let six = slab.insert(6);
|
||||||
|
assert_eq!(six.index, 0);
|
||||||
|
assert_eq!(six.generation, 0);
|
||||||
|
|
||||||
|
let seven = slab.insert(7);
|
||||||
|
assert_eq!(seven.index, 1);
|
||||||
|
assert_eq!(seven.generation, 0);
|
||||||
|
|
||||||
|
let six_mut = slab.get_mut(six);
|
||||||
|
assert!(six_mut.is_some());
|
||||||
|
|
||||||
|
let six_mut = six_mut.unwrap();
|
||||||
|
assert_eq!(six_mut, &mut 6);
|
||||||
|
|
||||||
|
*six_mut = 60;
|
||||||
|
assert_eq!(six_mut, &mut 60);
|
||||||
|
|
||||||
|
slab.remove(six);
|
||||||
|
|
||||||
|
let six_ref = slab.get_mut(six);
|
||||||
|
assert!(six_ref.is_none());
|
||||||
|
|
||||||
|
let eight = slab.insert(8);
|
||||||
|
assert_eq!(eight.index, 0);
|
||||||
|
assert_eq!(eight.generation, 1);
|
||||||
|
|
||||||
|
let eight_ref = slab.get_mut(eight);
|
||||||
|
assert!(eight_ref.is_some());
|
||||||
|
assert_eq!(eight_ref.unwrap(), &mut 8);
|
||||||
|
|
||||||
|
let six_ref = slab.get_mut(six);
|
||||||
|
assert!(six_ref.is_none());
|
||||||
|
}
|
||||||
|
}
|
813
lib/slab-tree/src/tree.rs
Normal file
813
lib/slab-tree/src/tree.rs
Normal file
@ -0,0 +1,813 @@
|
|||||||
|
use crate::behaviors::*;
|
||||||
|
use crate::core_tree::CoreTree;
|
||||||
|
use crate::node::*;
|
||||||
|
use crate::NodeId;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// A `Tree` builder. Provides more control over how a `Tree` is created.
|
||||||
|
///
|
||||||
|
pub struct TreeBuilder<T> {
|
||||||
|
root: Option<T>,
|
||||||
|
capacity: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for TreeBuilder<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
TreeBuilder::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TreeBuilder<T> {
|
||||||
|
///
|
||||||
|
/// Creates a new `TreeBuilder` with the default settings.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let _tree_builder = TreeBuilder::new();
|
||||||
|
///
|
||||||
|
/// # _tree_builder.with_root(1);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn new() -> TreeBuilder<T> {
|
||||||
|
TreeBuilder {
|
||||||
|
root: None,
|
||||||
|
capacity: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the root `Node` of the `TreeBuilder`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let _tree_builder = TreeBuilder::new().with_root(1);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn with_root(self, root: T) -> TreeBuilder<T> {
|
||||||
|
TreeBuilder {
|
||||||
|
root: Some(root),
|
||||||
|
capacity: self.capacity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the capacity of the `TreeBuilder`.
|
||||||
|
///
|
||||||
|
/// This can be used to pre-allocate space in the `Tree` if you know you'll be adding a large
|
||||||
|
/// number of `Node`s to the `Tree`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let _tree_builder = TreeBuilder::new().with_capacity(10);
|
||||||
|
///
|
||||||
|
/// # _tree_builder.with_root(1);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn with_capacity(self, capacity: usize) -> TreeBuilder<T> {
|
||||||
|
TreeBuilder {
|
||||||
|
root: self.root,
|
||||||
|
capacity: Some(capacity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Build a `Tree` based upon the current settings in the `TreeBuilder`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let _tree = TreeBuilder::new().with_root(1).with_capacity(10).build();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn build(self) -> Tree<T> {
|
||||||
|
let capacity = self.capacity.unwrap_or(0);
|
||||||
|
let mut core_tree: CoreTree<T> = CoreTree::new(capacity);
|
||||||
|
let root_id = self.root.map(|val| core_tree.insert(val));
|
||||||
|
|
||||||
|
Tree { root_id, core_tree }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// A tree structure containing `Node`s.
|
||||||
|
///
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct Tree<T> {
|
||||||
|
pub(crate) root_id: Option<NodeId>,
|
||||||
|
pub(crate) core_tree: CoreTree<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Tree<T> {
|
||||||
|
///
|
||||||
|
/// Creates a new `Tree` with a capacity of 0.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::Tree;
|
||||||
|
///
|
||||||
|
/// let tree: Tree<i32> = Tree::new();
|
||||||
|
///
|
||||||
|
/// # assert_eq!(tree.capacity(), 0);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn new() -> Tree<T> {
|
||||||
|
TreeBuilder::new().build()
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: write test for this
|
||||||
|
///
|
||||||
|
/// Sets the "root" of the `Tree` to be `root`.
|
||||||
|
///
|
||||||
|
/// If there is already a "root" node in the `Tree`, that node is shifted down and the new
|
||||||
|
/// one takes its place.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::Tree;
|
||||||
|
///
|
||||||
|
/// let mut tree = Tree::new();
|
||||||
|
///
|
||||||
|
/// let root_id = tree.set_root(1);
|
||||||
|
///
|
||||||
|
/// assert_eq!(tree.root_id().unwrap(), root_id);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn set_root(&mut self, root: T) -> NodeId {
|
||||||
|
let old_root_id = self.root_id.take();
|
||||||
|
let new_root_id = self.core_tree.insert(root);
|
||||||
|
|
||||||
|
self.root_id = Some(new_root_id);
|
||||||
|
|
||||||
|
self.set_first_child(new_root_id, old_root_id);
|
||||||
|
self.set_last_child(new_root_id, old_root_id);
|
||||||
|
|
||||||
|
if let Some(node_id) = old_root_id {
|
||||||
|
self.set_parent(node_id, self.root_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_root_id
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the `Tree`'s current capacity. Capacity is defined as the number of times new
|
||||||
|
/// `Node`s can be added to the `Tree` before it must allocate more memory.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::Tree;
|
||||||
|
///
|
||||||
|
/// let tree: Tree<i32> = Tree::new();
|
||||||
|
///
|
||||||
|
/// assert_eq!(tree.capacity(), 0);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn capacity(&self) -> usize {
|
||||||
|
self.core_tree.capacity()
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the `NodeId` of the root node of the `Tree`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::Tree;
|
||||||
|
///
|
||||||
|
/// let mut tree = Tree::new();
|
||||||
|
/// tree.set_root(1);
|
||||||
|
///
|
||||||
|
/// let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// assert_eq!(tree.get(root_id).unwrap().data(), &1);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn root_id(&self) -> Option<NodeId> {
|
||||||
|
self.root_id
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `NodeRef` pointing to the root `Node` of the `Tree`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::Tree;
|
||||||
|
///
|
||||||
|
/// let mut tree = Tree::new();
|
||||||
|
/// tree.set_root(1);
|
||||||
|
///
|
||||||
|
/// let root = tree.root().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// assert_eq!(root.data(), &1);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn root(&self) -> Option<NodeRef<T>> {
|
||||||
|
self.root_id.map(|id| self.new_node_ref(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a `NodeMut` pointing to the root `Node` of the `Tree`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::Tree;
|
||||||
|
///
|
||||||
|
/// let mut tree = Tree::new();
|
||||||
|
/// tree.set_root(1);
|
||||||
|
///
|
||||||
|
/// let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||||
|
/// assert_eq!(root.data(), &mut 1);
|
||||||
|
///
|
||||||
|
/// *root.data() = 2;
|
||||||
|
/// assert_eq!(root.data(), &mut 2);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn root_mut(&mut self) -> Option<NodeMut<T>> {
|
||||||
|
self.root_id.map(move |id| self.new_node_mut(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the `NodeRef` pointing to the `Node` that the given `NodeId` identifies. If the
|
||||||
|
/// `NodeId` in question points to nothing (or belongs to a different `Tree`) a `None`-value
|
||||||
|
/// will be returned; otherwise, a `Some`-value will be returned.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::Tree;
|
||||||
|
///
|
||||||
|
/// let mut tree = Tree::new();
|
||||||
|
/// tree.set_root(1);
|
||||||
|
/// let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// let root = tree.get(root_id);
|
||||||
|
/// assert!(root.is_some());
|
||||||
|
///
|
||||||
|
/// let root = root.unwrap();
|
||||||
|
/// assert_eq!(root.data(), &1);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn get(&self, node_id: NodeId) -> Option<NodeRef<T>> {
|
||||||
|
let _ = self.core_tree.get(node_id)?;
|
||||||
|
Some(self.new_node_ref(node_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the `NodeMut` pointing to the `Node` that the given `NodeId` identifies. If the
|
||||||
|
/// `NodeId` in question points to nothing (or belongs to a different `Tree`) a `None`-value
|
||||||
|
/// will be returned; otherwise, a `Some`-value will be returned.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::Tree;
|
||||||
|
///
|
||||||
|
/// let mut tree = Tree::new();
|
||||||
|
/// tree.set_root(1);
|
||||||
|
/// let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
///
|
||||||
|
/// let root = tree.get_mut(root_id);
|
||||||
|
/// assert!(root.is_some());
|
||||||
|
///
|
||||||
|
/// let mut root = root.unwrap();
|
||||||
|
///
|
||||||
|
/// *root.data() = 2;
|
||||||
|
/// assert_eq!(root.data(), &mut 2);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn get_mut(&mut self, node_id: NodeId) -> Option<NodeMut<T>> {
|
||||||
|
let _ = self.core_tree.get_mut(node_id)?;
|
||||||
|
Some(self.new_node_mut(node_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Remove a `Node` by its `NodeId` and return the data that it contained.
|
||||||
|
/// Returns a `Some`-value if the `Node` exists; returns a `None`-value otherwise.
|
||||||
|
///
|
||||||
|
/// Children of the removed `Node` can either be dropped with `DropChildren` or orphaned with
|
||||||
|
/// `OrphanChildren`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
/// use slab_tree::behaviors::RemoveBehavior::*;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
/// let two_id = {
|
||||||
|
/// let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||||
|
/// let two_id = root.append(2).node_id();
|
||||||
|
/// root.append(3);
|
||||||
|
/// two_id
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let two = tree.remove(two_id, DropChildren);
|
||||||
|
///
|
||||||
|
/// assert!(two.is_some());
|
||||||
|
/// assert_eq!(two.unwrap(), 2);
|
||||||
|
///
|
||||||
|
/// let root = tree.root().expect("root doesn't exist?");
|
||||||
|
/// assert!(root.first_child().is_some());
|
||||||
|
/// assert_eq!(root.first_child().unwrap().data(), &mut 3);
|
||||||
|
///
|
||||||
|
/// assert!(root.last_child().is_some());
|
||||||
|
/// assert_eq!(root.last_child().unwrap().data(), &mut 3);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn remove(&mut self, node_id: NodeId, behavior: RemoveBehavior) -> Option<T> {
|
||||||
|
if let Some(node) = self.get_node(node_id) {
|
||||||
|
let Relatives {
|
||||||
|
parent,
|
||||||
|
prev_sibling,
|
||||||
|
next_sibling,
|
||||||
|
..
|
||||||
|
} = node.relatives;
|
||||||
|
|
||||||
|
let (is_first_child, is_last_child) = self.is_node_first_last_child(node_id);
|
||||||
|
|
||||||
|
if is_first_child {
|
||||||
|
// parent first child = my next sibling
|
||||||
|
self.set_first_child(parent.expect("parent must exist"), next_sibling);
|
||||||
|
}
|
||||||
|
if is_last_child {
|
||||||
|
// parent last child = my prev sibling
|
||||||
|
self.set_last_child(parent.expect("parent must exist"), prev_sibling);
|
||||||
|
}
|
||||||
|
if let Some(prev) = prev_sibling {
|
||||||
|
self.set_next_sibling(prev, next_sibling);
|
||||||
|
}
|
||||||
|
if let Some(next) = next_sibling {
|
||||||
|
self.set_prev_sibling(next, prev_sibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
match behavior {
|
||||||
|
RemoveBehavior::DropChildren => self.drop_children(node_id),
|
||||||
|
RemoveBehavior::OrphanChildren => self.orphan_children(node_id),
|
||||||
|
};
|
||||||
|
if self.root_id == Some(node_id) {
|
||||||
|
self.root_id = None;
|
||||||
|
}
|
||||||
|
self.core_tree.remove(node_id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_node(&self, node_id: NodeId) -> Option<&Node<T>> {
|
||||||
|
self.core_tree.get(node_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_node_mut(&mut self, node_id: NodeId) -> Option<&mut Node<T>> {
|
||||||
|
self.core_tree.get_mut(node_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_prev_siblings_next_sibling(
|
||||||
|
&mut self,
|
||||||
|
current_id: NodeId,
|
||||||
|
next_sibling: Option<NodeId>,
|
||||||
|
) {
|
||||||
|
if let Some(prev_sibling_id) = self.get_node_prev_sibling_id(current_id) {
|
||||||
|
self.set_next_sibling(prev_sibling_id, next_sibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_next_siblings_prev_sibling(
|
||||||
|
&mut self,
|
||||||
|
current_id: NodeId,
|
||||||
|
prev_sibling: Option<NodeId>,
|
||||||
|
) {
|
||||||
|
if let Some(next_sibling_id) = self.get_node_next_sibling_id(current_id) {
|
||||||
|
self.set_prev_sibling(next_sibling_id, prev_sibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_parent(&mut self, node_id: NodeId, parent_id: Option<NodeId>) {
|
||||||
|
if let Some(node) = self.get_node_mut(node_id) {
|
||||||
|
node.relatives.parent = parent_id;
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_prev_sibling(&mut self, node_id: NodeId, prev_sibling: Option<NodeId>) {
|
||||||
|
if let Some(node) = self.get_node_mut(node_id) {
|
||||||
|
node.relatives.prev_sibling = prev_sibling;
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_next_sibling(&mut self, node_id: NodeId, next_sibling: Option<NodeId>) {
|
||||||
|
if let Some(node) = self.get_node_mut(node_id) {
|
||||||
|
node.relatives.next_sibling = next_sibling;
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_first_child(&mut self, node_id: NodeId, first_child: Option<NodeId>) {
|
||||||
|
if let Some(node) = self.get_node_mut(node_id) {
|
||||||
|
node.relatives.first_child = first_child;
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_last_child(&mut self, node_id: NodeId, last_child: Option<NodeId>) {
|
||||||
|
if let Some(node) = self.get_node_mut(node_id) {
|
||||||
|
node.relatives.last_child = last_child;
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_node_prev_sibling_id(&self, node_id: NodeId) -> Option<NodeId> {
|
||||||
|
if let Some(node) = self.get_node(node_id) {
|
||||||
|
node.relatives.prev_sibling
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_node_next_sibling_id(&self, node_id: NodeId) -> Option<NodeId> {
|
||||||
|
if let Some(node) = self.get_node(node_id) {
|
||||||
|
node.relatives.next_sibling
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_node_relatives(&self, node_id: NodeId) -> Relatives {
|
||||||
|
if let Some(node) = self.get_node(node_id) {
|
||||||
|
node.relatives
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop_children(&mut self, node_id: NodeId) {
|
||||||
|
let sub_tree_ids: Vec<NodeId> = self
|
||||||
|
.get(node_id)
|
||||||
|
.expect("node must exist")
|
||||||
|
.traverse_level_order()
|
||||||
|
.skip(1) // skip the "root" of the sub-tree, which is the "current" node
|
||||||
|
.map(|node_ref| node_ref.node_id())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for id in sub_tree_ids {
|
||||||
|
self.core_tree.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn orphan_children(&mut self, node_id: NodeId) {
|
||||||
|
let child_ids: Vec<NodeId> = self
|
||||||
|
.get(node_id)
|
||||||
|
.expect("node must exist")
|
||||||
|
.children()
|
||||||
|
.map(|node_ref| node_ref.node_id())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for id in child_ids {
|
||||||
|
self.set_parent(id, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_node_ref(&self, node_id: NodeId) -> NodeRef<T> {
|
||||||
|
NodeRef::new(node_id, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_node_mut(&mut self, node_id: NodeId) -> NodeMut<T> {
|
||||||
|
NodeMut::new(node_id, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_node_first_last_child(&self, node_id: NodeId) -> (bool, bool) {
|
||||||
|
if let Some(node) = self.get_node(node_id) {
|
||||||
|
node.relatives
|
||||||
|
.parent
|
||||||
|
.and_then(|parent_id| self.get_node(parent_id))
|
||||||
|
.map(|parent| {
|
||||||
|
let Relatives {
|
||||||
|
first_child: first,
|
||||||
|
last_child: last,
|
||||||
|
..
|
||||||
|
} = parent.relatives;
|
||||||
|
(
|
||||||
|
first.map(|child_id| child_id == node_id).unwrap_or(false),
|
||||||
|
last.map(|child_id| child_id == node_id).unwrap_or(false),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or((false, false))
|
||||||
|
} else {
|
||||||
|
(false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for Tree<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
TreeBuilder::new().build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: std::fmt::Debug> Tree<T> {
|
||||||
|
/// Write formatted tree representation and nodes with debug formatting.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let mut tree = TreeBuilder::new().with_root(0).build();
|
||||||
|
/// let mut root = tree.root_mut().unwrap();
|
||||||
|
/// root.append(1)
|
||||||
|
/// .append(2);
|
||||||
|
/// root.append(3);
|
||||||
|
/// let mut s = String::new();
|
||||||
|
/// tree.write_formatted(&mut s).unwrap();
|
||||||
|
/// assert_eq!(&s, "\
|
||||||
|
/// 0
|
||||||
|
/// ├── 1
|
||||||
|
/// │ └── 2
|
||||||
|
/// └── 3
|
||||||
|
/// ");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Writes nothing if the tree is empty.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use slab_tree::tree::TreeBuilder;
|
||||||
|
///
|
||||||
|
/// let tree = TreeBuilder::<i32>::new().build();
|
||||||
|
/// let mut s = String::new();
|
||||||
|
/// tree.write_formatted(&mut s).unwrap();
|
||||||
|
/// assert_eq!(&s, "");
|
||||||
|
/// ```
|
||||||
|
pub fn write_formatted<W: std::fmt::Write>(&self, w: &mut W) -> std::fmt::Result {
|
||||||
|
if let Some(root) = self.root() {
|
||||||
|
let node_id = root.node_id();
|
||||||
|
let childn = 0;
|
||||||
|
let level = 0;
|
||||||
|
let last = vec![];
|
||||||
|
let mut stack = vec![(node_id, childn, level, last)];
|
||||||
|
while let Some((node_id, childn, level, last)) = stack.pop() {
|
||||||
|
debug_assert_eq!(
|
||||||
|
last.len(),
|
||||||
|
level,
|
||||||
|
"each previous level should indicate whether it has reached the last node"
|
||||||
|
);
|
||||||
|
let node = self
|
||||||
|
.get(node_id)
|
||||||
|
.expect("getting node of existing node ref id");
|
||||||
|
if childn == 0 {
|
||||||
|
for i in 1..level {
|
||||||
|
if last[i - 1] {
|
||||||
|
write!(w, " ")?;
|
||||||
|
} else {
|
||||||
|
write!(w, "│ ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if level > 0 {
|
||||||
|
if last[level - 1] {
|
||||||
|
write!(w, "└── ")?;
|
||||||
|
} else {
|
||||||
|
write!(w, "├── ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(w, "{:?}", node.data())?;
|
||||||
|
}
|
||||||
|
let mut children = node.children().skip(childn);
|
||||||
|
if let Some(child) = children.next() {
|
||||||
|
let mut next_last = last.clone();
|
||||||
|
if children.next().is_some() {
|
||||||
|
stack.push((node_id, childn + 1, level, last));
|
||||||
|
next_last.push(false);
|
||||||
|
} else {
|
||||||
|
next_last.push(true);
|
||||||
|
}
|
||||||
|
stack.push((child.node_id(), 0, level + 1, next_last));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tree_tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::behaviors::RemoveBehavior::{DropChildren, OrphanChildren};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capacity() {
|
||||||
|
let tree = TreeBuilder::new().with_root(1).with_capacity(5).build();
|
||||||
|
assert_eq!(tree.capacity(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn root_id() {
|
||||||
|
let tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root = tree.get(root_id).unwrap();
|
||||||
|
assert_eq!(root.data(), &1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_root_drop() {
|
||||||
|
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
|
||||||
|
tree.remove(root_id, RemoveBehavior::DropChildren);
|
||||||
|
assert!(tree.root().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_root_orphan() {
|
||||||
|
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
|
||||||
|
tree.remove(root_id, RemoveBehavior::OrphanChildren);
|
||||||
|
assert!(tree.root().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn root() {
|
||||||
|
let tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
let root = tree.root().expect("root doesn't exist?");
|
||||||
|
assert_eq!(root.data(), &1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn root_mut() {
|
||||||
|
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||||
|
|
||||||
|
assert_eq!(root.data(), &mut 1);
|
||||||
|
|
||||||
|
*root.data() = 2;
|
||||||
|
assert_eq!(root.data(), &mut 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get() {
|
||||||
|
let tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root = tree.get(root_id);
|
||||||
|
assert!(root.is_some());
|
||||||
|
|
||||||
|
let root = root.unwrap();
|
||||||
|
assert_eq!(root.data(), &1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_mut() {
|
||||||
|
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root = tree.get_mut(root_id);
|
||||||
|
assert!(root.is_some());
|
||||||
|
|
||||||
|
let mut root = root.unwrap();
|
||||||
|
assert_eq!(root.data(), &mut 1);
|
||||||
|
|
||||||
|
*root.data() = 2;
|
||||||
|
assert_eq!(root.data(), &mut 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_node() {
|
||||||
|
let tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root = tree.get_node(root_id);
|
||||||
|
assert!(root.is_some());
|
||||||
|
|
||||||
|
let root = root.unwrap();
|
||||||
|
assert_eq!(root.data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_node_mut() {
|
||||||
|
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
|
||||||
|
let root_id = tree.root_id().expect("root doesn't exist?");
|
||||||
|
let root = tree.get_node_mut(root_id);
|
||||||
|
assert!(root.is_some());
|
||||||
|
|
||||||
|
let root = root.unwrap();
|
||||||
|
assert_eq!(root.data, 1);
|
||||||
|
|
||||||
|
root.data = 2;
|
||||||
|
assert_eq!(root.data, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_drop() {
|
||||||
|
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
|
||||||
|
let two_id;
|
||||||
|
let three_id;
|
||||||
|
let four_id;
|
||||||
|
let five_id;
|
||||||
|
{
|
||||||
|
let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||||
|
two_id = root.append(2).node_id();
|
||||||
|
three_id = root.append(3).node_id();
|
||||||
|
four_id = root.append(4).node_id();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
five_id = tree
|
||||||
|
.get_mut(three_id)
|
||||||
|
.expect("three doesn't exist?")
|
||||||
|
.append(5)
|
||||||
|
.node_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1
|
||||||
|
// / | \
|
||||||
|
// 2 3 4
|
||||||
|
// |
|
||||||
|
// 5
|
||||||
|
|
||||||
|
tree.remove(three_id, DropChildren);
|
||||||
|
|
||||||
|
let root = tree
|
||||||
|
.get_node(tree.root_id().expect("tree doesn't exist?"))
|
||||||
|
.unwrap();
|
||||||
|
assert!(root.relatives.first_child.is_some());
|
||||||
|
assert!(root.relatives.last_child.is_some());
|
||||||
|
assert_eq!(root.relatives.first_child.unwrap(), two_id);
|
||||||
|
assert_eq!(root.relatives.last_child.unwrap(), four_id);
|
||||||
|
|
||||||
|
let two = tree.get_node(two_id);
|
||||||
|
assert!(two.is_some());
|
||||||
|
|
||||||
|
let two = two.unwrap();
|
||||||
|
assert_eq!(two.relatives.next_sibling, Some(four_id));
|
||||||
|
|
||||||
|
let four = tree.get_node(four_id);
|
||||||
|
assert!(four.is_some());
|
||||||
|
|
||||||
|
let four = four.unwrap();
|
||||||
|
assert_eq!(four.relatives.prev_sibling, Some(two_id));
|
||||||
|
|
||||||
|
let five = tree.get_node(five_id);
|
||||||
|
assert!(five.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test that there is no panic if caller tries to remove a removed node
|
||||||
|
#[test]
|
||||||
|
fn address_dropped() {
|
||||||
|
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
let two_id = tree.root_mut().expect("root doesn't exist").node_id();
|
||||||
|
tree.remove(two_id, DropChildren);
|
||||||
|
tree.remove(two_id, DropChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_orphan() {
|
||||||
|
let mut tree = TreeBuilder::new().with_root(1).build();
|
||||||
|
|
||||||
|
let two_id;
|
||||||
|
let three_id;
|
||||||
|
let four_id;
|
||||||
|
let five_id;
|
||||||
|
{
|
||||||
|
let mut root = tree.root_mut().expect("root doesn't exist?");
|
||||||
|
two_id = root.append(2).node_id();
|
||||||
|
three_id = root.append(3).node_id();
|
||||||
|
four_id = root.append(4).node_id();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
five_id = tree
|
||||||
|
.get_mut(three_id)
|
||||||
|
.expect("three doesn't exist?")
|
||||||
|
.append(5)
|
||||||
|
.node_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1
|
||||||
|
// / | \
|
||||||
|
// 2 3 4
|
||||||
|
// |
|
||||||
|
// 5
|
||||||
|
|
||||||
|
tree.remove(three_id, OrphanChildren);
|
||||||
|
|
||||||
|
let root = tree
|
||||||
|
.get_node(tree.root_id().expect("tree doesn't exist?"))
|
||||||
|
.unwrap();
|
||||||
|
assert!(root.relatives.first_child.is_some());
|
||||||
|
assert!(root.relatives.last_child.is_some());
|
||||||
|
assert_eq!(root.relatives.first_child.unwrap(), two_id);
|
||||||
|
assert_eq!(root.relatives.last_child.unwrap(), four_id);
|
||||||
|
|
||||||
|
let two = tree.get_node(two_id);
|
||||||
|
assert!(two.is_some());
|
||||||
|
|
||||||
|
let two = two.unwrap();
|
||||||
|
assert_eq!(two.relatives.next_sibling, Some(four_id));
|
||||||
|
|
||||||
|
let four = tree.get_node(four_id);
|
||||||
|
assert!(four.is_some());
|
||||||
|
|
||||||
|
let four = four.unwrap();
|
||||||
|
assert_eq!(four.relatives.prev_sibling, Some(two_id));
|
||||||
|
|
||||||
|
let five = tree.get_node(five_id);
|
||||||
|
assert!(five.is_some());
|
||||||
|
|
||||||
|
let five = five.unwrap();
|
||||||
|
assert_eq!(five.relatives.parent, None);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user