Skip to content

Commit

Permalink
Merge pull request #18 from calcit-lang/reduce-arc
Browse files Browse the repository at this point in the history
Reduce arc usages; add split method
  • Loading branch information
csvwolf authored Feb 13, 2024
2 parents 9f4c9a0 + 8b1deee commit 3bf6b55
Show file tree
Hide file tree
Showing 8 changed files with 603 additions and 192 deletions.
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 <[email protected]>"]
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

0 comments on commit 3bf6b55

Please sign in to comment.