Skip to content

Commit

Permalink
version 0.2.0
Browse files Browse the repository at this point in the history
1. [doc] Add description of potted tree in README.md.
2. [refactoring] Introducing `children()`/`children_mut()` again in `trees::linked`, but mark them as deprecated.
3. [refactoring] Remove unnecessary `clone()` for `potted::NodeMut`.
4. [bug] Set the vec's length to 0 in tree/forest's drop functions.
5. [feature] Add functions for `potted::Tree` which delegate to `root()`/`root_mut()`.
6. [refactoring] Add `potted::Pot<T>::next_sib()`.
  • Loading branch information
oooutlk committed Sep 26, 2018
1 parent c4bfb43 commit bc56065
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 20 deletions.
27 changes: 20 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This project provides various implementations of trees serving for general purpo

- Traversal

Each node in a tree provides standard forward iterators for visiting its children nodes. Tree traversal can be done via using these iterators in recursive function calls.
Each node in a tree provides standard forward iterators for visiting its children nodes. Tree traversal can be done using these iterators in recursive function calls.

Depth-first search and breadth-first iterators are also provided.

Expand All @@ -13,23 +13,35 @@ This project provides various implementations of trees serving for general purpo

The methods for adding or removing child tree at the front/back of a node’s children list are guaranteed constant time. Accessing, inserting or removing nodes in any position are linear time.

All public interfaces are safe.
The `potted` trees constructed in batch mode can randomly access the child nodes in constant time.

The library users does not need any `unsafe` code to use this library.


- Notation

A compact notation of tree construction has been developed by overloading sub and div operators. It makes complex tree composition look like literal expression, reducing a bit of syntax noise. See the example section for more.
Tow compact notations of tree construction has been developed by overloading sub and div operators. They make complex tree composition look like literal expression, reducing a bit of syntax noise.

The first notation is using operator overloading. Using operator '-' to express sibling relationship, and '/' to express parent-child relationship.
Something like `root /( first_child - second_child )`.

The second notation is using Rust tuple, something like `( root, first_child, second_child )`.

See the example section for more.

# Implementations

Currently this library provides only two slightly different trees, both implemented in raw-pointer-linked nodes.
Currently this library provides three different trees, implemented in raw-pointer-linked or vec-backed nodes.

- `linked::singly`
Two pointers per node. Hold no size infomation. Note that constant time `pop_back` is not supported.

- `linked::singly`
Four pointers plus two `u32`s per node. Hold children count and node count.

- `potted`
Seven `u32`s per node. Hold children count, node count and adjoined children count.

# Prominent types

Tree, Forest and Node are the big three types in this library.
Expand All @@ -38,17 +50,18 @@ Tree, Forest and Node are the big three types in this library.

- Forest is similar to Tree, except that it has no root node.

- Node is the underlying storage type and **opaque** to the library users. Instead, &Node and &mut Node are exposed.
- Node is the underlying storage type and **opaque** to the library users. Instead, `&Node`/`&mut Node` or `NodeRef`/`NodeMut` are exposed.

# Examples

- notation of a literal tree

```rust
let tree = tr(0) /( tr(1)/tr(2)/tr(3) ) /( tr(4)/tr(5)/tr(6) );
let linked_tree = tr(0) /( tr(1)/tr(2)/tr(3) ) /( tr(4)/tr(5)/tr(6) );
let potted_tree = potted::Tree::from(( 0, (1,2,3), (4,5,6) ));
```

It encodes a tree drawn as follows:
They both encode a tree drawn as follows:

.............
. 0 .
Expand Down
16 changes: 10 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@
//! {
//! let root: NodeRef<i32> = tree.root();
//! let first_child: NodeRef<i32> = tree.root().iter().next().unwrap();
//! let second_child: NodeRef<i32> = tree.root().nth_child(1).unwrap(); // in nearly constant time.
//! let second_child: NodeRef<i32> = tree.root().nth_child(1).unwrap(); // `nth_child()` is in constant time.
//! let third_child : NodeRef<i32> = tree.root().iter().last().unwrap();
//! }
//! ```
Expand All @@ -221,7 +221,9 @@
//!
//! 2. Using `iter_mut()` to iterate over referenced child `Node`s, you can:
//!
//! 2.1 read/write the data associated with each node, or `prepend()`, `append`, `abandon()`, `push_front()`, `pop_front()`, `push_back()` child node(s) in constant time.
//! 2.1 read/write the data associated with each node, or `prepend()`, `append`, `abandon()`, `push_front()`, `pop_front()`, `push_back()`, `pop_back()` child node(s) in constant time.
//!
//! Note that `linked::singly` does not have `pop_back()`, and `potted` tree/forest's methods are different in names and/or functionalities.
//!
//! 2.2 use `iter_mut()` to iterate over children's children, etc.
//!
Expand All @@ -247,6 +249,8 @@
//!
//! 2. visit `Node`s irregularly, unlike the iterators mentioned above that are usually called intensively.
//!
//! Note that it is not implemented yet for potted version.
//!
//! ### Resource management
//!
//! 1. `Tree`/`Forest` will recursively destruct all the nodes owned by them when reaching the end of their lifetimes.
Expand All @@ -261,7 +265,7 @@
//!
//! 2. `Tree`/`Forest` provides owned iterator `fn bfs_into_iter( self )`.
//!
//! 3. potted `Tree`/`Forest` directly supports `From`/`Into` BFS streams.
//! 3. All version of `Tree`/`Forest`/`Node` support `Into` BFS streams, while potted version supports `From` BFS streams also.
//!
//! ### Panics
//!
Expand All @@ -271,7 +275,7 @@
//! * `Forest::<T>::clone()`
//! * all of the operator overloading functions the operands of which contain at least one referenced type.
//!
//! Another cause is a few assertions in potted version.
//! A few assertions in potted version can also cause panics.
//!
//! ### Safety
//!
Expand All @@ -283,7 +287,7 @@
//! ```compile_fail
//! use trees::tr;
//!
//! let root; // node reference can not live out of tree
//! let root; // node reference can not live longer than tree
//! {
//! let tree = tr(0);
//! root = tree.root();
Expand All @@ -293,7 +297,7 @@
//! ```compile_fail
//! use trees::tr;
//!
//! let root; // mutable node reference can not live out of tree
//! let root; // mutable node reference can not longer than tree
//! {
//! let mut tree = tr(0);
//! root = tree.root_mut();
Expand Down
18 changes: 18 additions & 0 deletions src/linked/fully/forest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,15 @@ impl<T> Forest<T> {
}}
}

#[deprecated( since="0.2.0", note="please use `iter` instead" )]
#[inline] pub fn children<'a>( &self ) -> Iter<'a,T> {
if self.is_empty() {
Iter::new( null(), null(), 0 )
} else { unsafe {
Iter::new( self.head(), self.tail(), self.size.degree as usize )
}}
}

/// Provides a forward iterator over child `Node`s with mutable references.
///
/// # Examples
Expand All @@ -338,6 +347,15 @@ impl<T> Forest<T> {
}}
}

#[deprecated( since="0.2.0", note="please use `iter_mut` instead" )]
#[inline] pub fn children_mut<'a>( &mut self ) -> IterMut<'a,T> {
if self.is_empty() {
IterMut::new( null_mut(), null_mut(), 0 )
} else { unsafe {
IterMut::new( self.head(), self.tail(), self.size.degree as usize )
}}
}

/// Provide an iterator over `Forest`'s `Subnode`s for insert/remove at any position.
/// See `Subnode`'s document for more.
#[inline] pub fn onto_iter<'a>( &mut self ) -> OntoIter<'a,T> {
Expand Down
18 changes: 18 additions & 0 deletions src/linked/fully/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,15 @@ impl<T> Node<T> {
}}
}

#[deprecated( since="0.2.0", note="please use `iter` instead" )]
#[inline] pub fn children<'a, 's:'a>( &'s self ) -> Iter<'a,T> {
if self.is_leaf() {
Iter::new( null(), null(), 0 )
} else { unsafe {
Iter::new( self.head(), self.tail(), self.size.degree as usize )
}}
}

/// Provides a forward iterator over child `Node`s with mutable references.
///
/// # Examples
Expand All @@ -391,6 +400,15 @@ impl<T> Node<T> {
}}
}

#[deprecated( since="0.2.0", note="please use `iter_mut` instead" )]
#[inline] pub fn children_mut<'a, 's:'a>( &'s mut self ) -> IterMut<'a,T> {
if self.is_leaf() {
IterMut::new( null_mut(), null_mut(), 0 )
} else { unsafe {
IterMut::new( self.head(), self.tail(), self.size.degree as usize )
}}
}

/// Provide an iterator over `Node`'s `Subnode`s for insert/remove at any position.
/// See `Subnode`'s document for more.
#[inline] pub fn onto_iter<'a, 's:'a>( &'s mut self ) -> OntoIter<'a,T> {
Expand Down
2 changes: 2 additions & 0 deletions src/potted/forest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::bfs::{Bfs,BfsForest,Splitted,Moved,Visit};

use rust::*;

#[derive(Debug)]
pub struct Forest<T> {
pub(crate) pot : Pot<T>,
}
Expand Down Expand Up @@ -223,6 +224,7 @@ impl<T> Drop for Forest<T> {
fn drop( &mut self ) {
if !self.pot.nodes.is_empty() {
self.iter_mut().for_each( |node| node.drop_all_data_if_needed() );
unsafe{ self.pot.nodes.set_len(0); }
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/potted/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
//! Some interesting features of the potted trees are:
//!
//! 1. They can be written in the form of Rust tuple.
//! Only the tuples composed of no more than a limited fields (now 32) are supported due to the lack of variadic generics in current Rust.
//! And the library user is required to impl the mark trait `TreeData` for the type other than primitives or strings to be the data type of the tree.
//!
//! 2. The child nodes can be randomly accessed in constant time, as long as the tree/forest is constructed in batch mode, and do few modifications after that.
//!
Expand Down
6 changes: 2 additions & 4 deletions src/potted/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,13 +348,11 @@ impl<'a, T:'a> NodeMut<'a,T> {
}
}

fn clone( &self ) -> Self { Self{ ..*self }}

fn drop_data_recursively( &self ) {
for child in self.clone().iter_mut() {
for child in self.iter_mut() {
child.drop_data_recursively();
}
unsafe{ ptr::drop_in_place( self.clone().data_mut() )}
unsafe{ ptr::drop_in_place( self.data_mut() )}
}

pub(crate) fn drop_all_data_if_needed( &self ) {
Expand Down
1 change: 1 addition & 0 deletions src/potted/notation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::{Pot,Size};

use rust::*;

/// mark trait for types to be the data type of the tree/forest.
pub trait TreeData: Sized {}

macro_rules! primitive_impls {
Expand Down
20 changes: 18 additions & 2 deletions src/potted/pot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl<T> Pot<T> {
unsafe{ self.nodes.set_len( len + node_cnt ); }
}

// unsafe version of push_back, no update on parent's `degree` or propagation of `node_cnt`
// unsafe push_back, no update on parent's `degree` or propagation of `node_cnt`
#[inline] pub(crate) fn gather( &mut self, parent: usize, child: usize, data: T, size: Size ) {
let mut node = Node {
next : child as u32,
Expand Down Expand Up @@ -92,6 +92,22 @@ impl<T> Pot<T> {

#[inline] pub(crate) fn next( &self, index: usize ) -> usize { self.nodes[ index ].next as usize }

// get the true next sib node, with "forest node" in mind.
#[allow(dead_code)]
#[inline]
pub(crate) fn next_sib( &self, index: usize ) -> usize {
let parent = self.parent( index );
if parent.is_null() || !self.is_forest( parent ) { // it is inside a normal node
self.next( index )
} else { // it is inside a forest node
if index == self.tail( parent ) {
self.next( parent )
} else {
self.next( index )
}
}
}

#[inline] pub(crate) fn adjoined( &self, index: usize )-> usize { self.nodes[ index ].adjoined as usize }

#[inline] pub(crate) fn data<'s>( &'s self, index: usize ) -> &'s T { &self.nodes[ index ].data }
Expand Down Expand Up @@ -122,7 +138,7 @@ impl<T> Pot<T> {
if self.tail( index ).is_null() {
usize::null()
} else {
self.nodes[ self.tail( index ) ].next()
self.nodes[ self.tail( index ) ].next() // forest is ok to be head as long as all calls of head() is for modifying structure rather than finding a node.
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/potted/tree.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use super::{Pot,Forest,NodeRef,NodeMut,MovedNodes,Iter,TupleTree,TupleForest,Index};
use super::{Pot,Forest,NodeRef,NodeMut,MovedNodes,Iter,IterMut,TupleTree,TupleForest,Index};

use super::bfs::{Bfs,BfsTree,Splitted,Visit,Moved};

use rust::*;

#[derive(Debug)]
pub struct Tree<T> {
pub(crate) pot : Pot<T>,
}
Expand Down Expand Up @@ -71,6 +72,9 @@ impl<T> Tree<T> {
BfsTree{ iter, size }
}

pub fn iter<'a, 's:'a>( &'s self ) -> Iter<'a,T> { self.root().iter() }
pub fn iter_mut<'a, 's:'a>( &'s mut self ) -> IterMut<'a,T> { self.root_mut().iter_mut() }

pub fn prepend_tr<Tr>( &mut self, tuple: Tr ) where Tr: TupleTree<Data=T> { self.root_mut().prepend_tr( tuple ); }
pub fn append_tr<Tr>( &mut self, tuple: Tr ) where Tr: TupleTree<Data=T> { self.root_mut().append_tr( tuple ); }
pub fn insert_tr<Tuple>( &mut self, nth: usize, tuple: Tuple ) where Tuple: TupleTree<Data=T> { self.root_mut().insert_tr( nth, tuple ); }
Expand Down Expand Up @@ -112,6 +116,7 @@ impl<T> Drop for Tree<T> {
fn drop( &mut self ) {
if !self.pot.nodes.is_empty() {
self.root_mut().drop_all_data_if_needed();
unsafe{ self.pot.nodes.set_len(0); }
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/size.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[cfg(feature="no_std")]
use rust::*;

/// A struct keeping the node's children count and all its descendants count for resource management purpose.
/// Note that `u32` is utilized rather than `usize`, because 4194304K ought to be enough for anybody.
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
pub struct Size {
pub degree : u32, // count of children node
Expand Down

0 comments on commit bc56065

Please sign in to comment.