Skip to content

Reduce arc usages; add split method #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
Cargo.lock

flamegraph.svg

profile.json
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

[package]
name = "im_ternary_tree"
version = "0.0.11"
version = "0.0.14"
edition = "2021"
authors = ["jiyinyiyong <jiyinyiyong@gmail.com>"]
license = "MIT"
Expand Down
16 changes: 14 additions & 2 deletions examples/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,23 @@ use im_ternary_tree::TernaryTreeList;
pub fn main() -> Result<(), String> {
let mut tree: TernaryTreeList<usize> = TernaryTreeList::Empty;

for idx in 0..80 {
let n = 20000000;

for idx in 0..n {
// println!();
tree = tree.push_left(idx);
println!("{}", tree.format_inline());
// println!("{}", tree.format_inline());
}

println!("{}", tree.len());

for _ in 0..n {
// println!();
tree = tree.drop_right();
// println!("{}", tree.format_inline());
}

println!("{}", tree.len());

Ok(())
}
104 changes: 91 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,34 @@ where
}
}

/// items in debug display
pub fn format_debug(&self) -> String {
let mut s = String::from("(TernaryTreeList debug");
for x in self.iter() {
s.push_str(&format!(" {:?}", x));
}
s.push(')');
s
}

/// get element in list by reference
/// PERF: recursive function is slower than iterative loop with Cell in bench(using `usize`),
/// however, Calcit is heavy in cloning(reference though... according real practice),
/// so here we still choose `ref_get` for speed in Calcit project.
pub fn get(&self, idx: usize) -> Option<&T> {
if self.is_empty() || idx >= self.len() {
let l = self.len();
if l == 0 || idx >= l {
None
} else if idx == 0 {
match self {
Empty => None,
Tree(t) => t.ref_first(),
}
} else if idx == l - 1 {
match self {
Empty => None,
Tree(t) => t.ref_last(),
}
} else {
self.ref_get(idx)
}
Expand All @@ -90,6 +111,14 @@ where
}
}

/// index of element from end, return 0 if found at last
pub fn last_index_of(&self, item: &T) -> Option<usize> {
match self {
Empty => None,
Tree(t) => t.last_index_of(item),
}
}

/// recursively check structure
pub fn eq_shape(&self, ys: &Self) -> bool {
match (self, ys) {
Expand Down Expand Up @@ -130,6 +159,8 @@ where
Tree(t) => t.last(),
}
}

// at known index, update value
pub fn assoc(&self, idx: usize, item: T) -> Result<Self, String> {
match self {
Empty => Err(String::from("empty")),
Expand Down Expand Up @@ -184,13 +215,19 @@ where
match self {
Empty => {
if idx == 0 {
Ok(TernaryTreeList::Tree(TernaryTree::Leaf(Arc::new(item))))
Ok(TernaryTreeList::Tree(TernaryTree::Leaf(item)))
} else {
Err(String::from("inserting into empty, but index is not 0"))
}
}

Tree(t) => Ok(TernaryTreeList::Tree(t.insert(idx, item, after)?)),
Tree(t) => {
if after {
Ok(TernaryTreeList::Tree(t.insert_after(idx, item)?))
} else {
Ok(TernaryTreeList::Tree(t.insert_before(idx, item)?))
}
}
}
}
pub fn assoc_before(&self, idx: usize, item: T) -> Result<Self, String> {
Expand All @@ -212,7 +249,7 @@ where
}
pub fn prepend(&self, item: T) -> Self {
match self {
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(Arc::new(item))),
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(item)),
Tree(t) => TernaryTreeList::Tree(t.prepend(item)),
}
}
Expand All @@ -222,21 +259,21 @@ where
/// insert_after last element, this not optimzed for performance
pub fn append(&self, item: T) -> Self {
match self {
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(Arc::new(item))),
Tree(t) => TernaryTreeList::Tree(t.append(item)),
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(item)),
Tree(t) => TernaryTreeList::Tree(t.push_right(item)),
}
}
/// optimized for amortized `O(1)` performance at best cases
pub fn push_right(&self, item: T) -> Self {
match self {
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(Arc::new(item))),
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(item)),
Tree(t) => TernaryTreeList::Tree(t.push_right(item)),
}
}
/// optimized for amortized `O(1)` performance at best cases
pub fn push_left(&self, item: T) -> Self {
match self {
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(Arc::new(item))),
Empty => TernaryTreeList::Tree(TernaryTree::Leaf(item)),
Tree(t) => TernaryTreeList::Tree(t.push_left(item)),
}
}
Expand Down Expand Up @@ -284,6 +321,24 @@ where
}
}

/// split into 2 lists, either could be Empty
/// notice if index is too large, (Self, Empty) is returned, not providing index out of bound error
pub fn split(self, idx: usize) -> (Self, Self) {
if idx == 0 {
(Self::Empty, self)
} else if idx >= self.len() {
(self, Self::Empty)
} else {
match self {
Empty => (Self::Empty, Self::Empty),
Tree(t) => {
let (l, r) = t.split(idx);
(Self::Tree(l), Self::Tree(r))
}
}
}
}

/// optimized for amortized `O(1)` at best cases, but copies a lot
pub fn drop_right_shallow(&self) -> Self {
match self {
Expand Down Expand Up @@ -345,10 +400,33 @@ where
}

pub fn skip(&self, idx: usize) -> Result<Self, String> {
self.slice(idx, self.len())
// self.slice(idx, self.len())

match self {
Empty => Ok(TernaryTreeList::Empty),
Tree(t) => {
let size = t.len();
match idx.cmp(&size) {
Ordering::Equal => Ok(TernaryTreeList::Empty),
Ordering::Greater => Err(format!("Skip range too large {} for {}", idx, self.format_inline())),
Ordering::Less => Ok(TernaryTreeList::Tree(t.take_right(idx)?)),
}
}
}
}
pub fn take(&self, idx: usize) -> Result<Self, String> {
self.slice(0, idx)
match self {
Empty => Ok(TernaryTreeList::Empty),
Tree(t) => {
if idx == 0 {
Ok(TernaryTreeList::Empty)
} else if idx > self.len() {
Err(format!("Take range too large {} for {}", idx, self.format_inline()))
} else {
Ok(TernaryTreeList::Tree(t.take_left(idx)?))
}
}
}
}

pub fn reverse(&self) -> Self {
Expand Down Expand Up @@ -498,7 +576,7 @@ where
} else {
let mut ys: Vec<TernaryTree<T>> = Vec::with_capacity(xs.len());
for x in &xs {
ys.push(Leaf(Arc::new(x.to_owned())))
ys.push(Leaf(x.to_owned()))
}

TernaryTreeList::Tree(TernaryTree::rebuild_list(xs.len(), 0, &ys, 2))
Expand All @@ -516,7 +594,7 @@ where
} else {
let mut ys: Vec<TernaryTree<T>> = Vec::with_capacity(xs.len());
for x in xs {
ys.push(Leaf(Arc::new(x.to_owned())))
ys.push(Leaf(x.to_owned()))
}

TernaryTreeList::Tree(TernaryTree::rebuild_list(xs.len(), 0, &ys, 2))
Expand All @@ -535,7 +613,7 @@ where
} else {
let mut ys: Vec<TernaryTree<T>> = Vec::with_capacity(xs.len());
for x in xs {
ys.push(Leaf(Arc::new(x.to_owned())))
ys.push(Leaf(x.to_owned()))
}

TernaryTreeList::Tree(TernaryTree::rebuild_list(xs.len(), 0, &ys, 2))
Expand Down
Loading